<commit_before>
/*
 * Copyright (C) 2010 Red Hat, Inc.
 * Copyright IBM Corp. 2009
 *
 * phyp_driver.c: ssh layer to access Power Hypervisors
 *
 * Authors:
 *  <NAME> <otubo at linux.vnet.ibm.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <libssh2.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <domain_event.h>

#include "internal.h"
#include "authhelper.h"
#include "util.h"
#include "datatypes.h"
#include "buf.h"
#include "memory.h"
#include "logging.h"
#include "driver.h"
#include "libvirt/libvirt.h"
#include "virterror_internal.h"
#include "uuid.h"
#include "domain_conf.h"
#include "nodeinfo.h"

#include "phyp_driver.h"

#define VIR_FROM_THIS VIR_FROM_PHYP

#define PHYP_ERROR(code, ...)                                                 \
    virReportErrorHelper(NULL, VIR_FROM_PHYP, code, __FILE__, __FUNCTION__,   \
                         __LINE__, __VA_ARGS__)

/*
 * URI: phyp://user@[hmc|ivm]/managed_system
 * */

static virDrvOpenStatus
phypOpen(virConnectPtr conn,
         virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
{
    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;

    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 (conn->uri->path == NULL) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("Missing managed system name in phyp:// URI"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (VIR_ALLOC(phyp_driver) < 0) {
        virReportOOMError();
        goto failure;
    }

    if (VIR_ALLOC(uuid_table) < 0) {
        virReportOOMError();
        goto failure;
    }

    if (VIR_ALLOC(connection_data) < 0) {
        virReportOOMError();
        goto failure;
    }

    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;

    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 (phypUUIDTable_Init(conn) == -1)
        goto failure;

    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;
}

static int
phypClose(virConnectPtr conn)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;

    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);

    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 *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
               int *internal_socket)
{
    LIBSSH2_SESSION *session;
    const char *hostname = conn->uri->server;
    char *username = NULL;
    char *password = NULL;
    int sock;
    int rc;
    struct addrinfo *ai = NULL, *cur;
    struct addrinfo hints;
    int ret;
    char *pubkey = NULL;
    char *pvtkey = NULL;
    char *userhome = virGetUserDirectory(geteuid());
    struct stat pvt_stat, pub_stat;

    if (userhome == NULL)
        goto err;

    if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0) {
        virReportOOMError();
        goto err;
    }

    if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0) {
        virReportOOMError();
        goto err;
    }

    if (conn->uri->user != NULL) {
        username = strdup(conn->uri->user);

        if (username == NULL) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (auth == NULL || auth->cb == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("No authentication callback provided."));
            goto err;
        }

        username = virRequestUsername(auth, NULL, conn->uri->server);

        if (username == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
            goto err;
        }
    }

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    ret = getaddrinfo(hostname, "22", &hints, &ai);
    if (ret != 0) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Error while getting %s address info"), hostname);
        goto err;
    }

    cur = ai;
    while (cur != NULL) {
        sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
        if (sock >= 0) {
            if (connect(sock, cur->ai_addr, cur->ai_addrlen) == 0) {
                goto connected;
            }
            close(sock);
        }
        cur = cur->ai_next;
    }

    PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
               _("Failed to connect to %s"), hostname);
    freeaddrinfo(ai);
    goto err;

  connected:

    (*internal_socket) = sock;

    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
        goto err;

    /* tell libssh2 we want it all done non-blocking */
    libssh2_session_set_blocking(session, 0);

    while ((rc = libssh2_session_startup(session, sock)) ==
           LIBSSH2_ERROR_EAGAIN) ;
    if (rc) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("Failure establishing SSH session."));
        goto disconnect;
    }

    /* Trying authentication by pubkey */
    if (stat(pvtkey, &pvt_stat) || stat(pubkey, &pub_stat)) {
        rc = LIBSSH2_ERROR_SOCKET_NONE;
        goto keyboard_interactive;
    }

    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
           LIBSSH2_ERROR_EAGAIN) ;

  keyboard_interactive:
    if (rc == LIBSSH2_ERROR_SOCKET_NONE
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
        if (auth == NULL || auth->cb == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("No authentication callback provided."));
            goto disconnect;
        }

        password = <PASSWORD>(auth, username, conn->uri->server);

        if (password == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
            goto disconnect;
        }

        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
               LIBSSH2_ERROR_EAGAIN) ;

        if (rc) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("Authentication failed"));
            goto disconnect;
        } else
            goto exit;

    } else if (rc == LIBSSH2_ERROR_NONE) {
        goto exit;

    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
        goto err;
    }

  disconnect:
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
  err:
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return NULL;

  exit:
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    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)
{
    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 (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);
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&tex_ret);
}

/* return the lpar_id given a name and a managed system name */
static int
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
{
    int exit_status = 0;
    int lpar_id = 0;
    char *char_ptr;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s --filter lpar_names=%s -F lpar_id",
                    managed_system, name) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    if (virStrToLong_i(ret, &char_ptr, 10, &lpar_id) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return lpar_id;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

/* return the lpar name given a lpar_id and a managed system name */
static char *
phypGetLparNAME(LIBSSH2_SESSION * session, const char *managed_system,
                unsigned int lpar_id, virConnectPtr conn)
{
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F name",
                    managed_system, lpar_id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char *char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    VIR_FREE(cmd);
    return ret;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return NULL;
}


/* Search into the uuid_table for a lpar_uuid given a lpar_id
 * and a managed system name
 *
 * return:  0 - record found
 *         -1 - not found
 * */
int
phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
    unsigned int i = 0;

    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
            memmove(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
            return 0;
        }
    }

    return -1;
}

/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int memory = 0;
    int exit_status = 0;

    if (type != 1 && type != 0)
        goto err;

    if (type) {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r mem --level lpar -F curr_mem "
                        "--filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r mem --level lpar -F "
                        "curr_max_mem --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &memory) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return memory;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

}

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
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int exit_status = 0;
    int vcpus = 0;

    if (type) {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r proc --level lpar -F "
                        "curr_max_procs --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r proc --level lpar -F "
                        "curr_procs --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    }
    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &vcpus) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return (unsigned long) vcpus;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;
}

int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int remote_slot = 0;
    int exit_status = 0;

    if (virAsprintf(&cmd,
                    "lshwres -m %s -r virtualio --rsubtype scsi -F "
                    "remote_slot_num --filter lpar_names=%s",
                    managed_system, lpar_name) < 0) {
        virReportOOMError();
        goto err;
    }
    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &remote_slot) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return remote_slot;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

char *
phypGetBackingDevice(virConnectPtr conn, const char *managed_system,
                     char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    int remote_slot = 0;
    int exit_status = 0;
    char *char_ptr;
    char *backing_device = NULL;

    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        goto err;

    if (virAsprintf(&cmd,
                    "lshwres -m %s -r virtualio --rsubtype scsi -F "
                    "backing_devices --filter slots=%d",
                    managed_system, remote_slot) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    /* here is a little trick to deal returns of this kind:
     *
     * 0x8100000000000000//lv01
     *
     * the information we really need is only lv01, so we
     * need to skip a lot of things on the string.
     * */
    char_ptr = strchr(ret, '/');

    if (char_ptr) {
        char_ptr++;
        if (char_ptr[0] == '/')
            char_ptr++;
        else
            goto err;

        backing_device = strdup(char_ptr);

        if (backing_device == NULL) {
            virReportOOMError();
            goto err;
        }
    } else {
        backing_device = ret;
        ret = NULL;
    }

    char_ptr = strchr(backing_device, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return backing_device;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return NULL;

}

int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
{
    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;
    char *char_ptr = NULL;
    char *managed_system = phyp_driver->managed_system;
    int state = VIR_DOMAIN_NOSTATE;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s -F state --filter lpar_ids=%d",
                    managed_system, lpar_id) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto cleanup;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (STREQ(ret, "Running"))
        state = VIR_DOMAIN_RUNNING;
    else if (STREQ(ret, "Not Activated"))
        state = VIR_DOMAIN_SHUTOFF;
    else if (STREQ(ret, "Shutting Down"))
        state = VIR_DOMAIN_SHUTDOWN;

  cleanup:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return state;
}

int
phypGetVIOSPartitionID(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;
    int id = -1;
    char *char_ptr;
    char *managed_system = phyp_driver->managed_system;

    if (virAsprintf(&cmd,
                    "lssyscfg -m %s -r lpar -F lpar_id,lpar_env|grep "
                    "vioserver|sed -s 's/,.*$//g'", managed_system) < 0) {
        virReportOOMError();
        goto err;
    }

    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
phypDiskType(virConnectPtr conn, char *backing_device)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;
    char *char_ptr;
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    int disk_type = -1;

    if (virAsprintf(&cmd,
                    "viosvrcmd -m %s -p %d -c \"lssp -field name type "
                    "-fmt , -all|grep %s|sed -e 's/^.*,//g'\"",
                    managed_system, vios_id, backing_device) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto cleanup;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (STREQ(ret, "LVPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_BLOCK;
    else if (STREQ(ret, "FBPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_FILE;

  cleanup:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    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 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;

    if (type == 0)
        state = "|grep Running";
    else if (type == 1)
        state = "|grep \"Not Activated\"";
    else
        state = " ";

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s -F lpar_id,state %s |grep -c "
                    "^[0-9]*", managed_system, state) < 0) {
        virReportOOMError();
        goto err;
    }

    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)
{
    return phypNumDomainsGeneric(conn, 1);
}

static int
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;
    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;

    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

    memset(id_c, 0, 10);

    if (virAsprintf
        (&cmd,
         "lssyscfg -r lpar -m %s -F lpar_id,state %s | sed -e 's/,.*$//g'",
         managed_system, state) < 0) {
        virReportOOMError();
        goto err;
    }
    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)
{
    return phypListDomainsGeneric(conn, ids, nids, 0);
}

static int
phypListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    int got = 0;
    int i;
    char *cmd = NULL;
    char *ret = NULL;
    char *domains = NULL;
    char *char_ptr2 = NULL;

    if (virAsprintf
        (&cmd,
         "lssyscfg -r lpar -m %s -F name,state | grep \"Not Activated\" | "
         "sed -e 's/,.*$//g'", managed_system) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    /* I need to parse the textual return in order to get the domains */
    if (exit_status < 0 || ret == NULL)
        goto err;
    else {
        domains = ret;

        while (got < nnames) {
            char_ptr2 = strchr(domains, '\n');

            if (char_ptr2) {
                *char_ptr2 = '\0';
                if ((names[got++] = strdup(domains)) == NULL) {
                    virReportOOMError();
                    goto err;
                }
                char_ptr2++;
                domains = char_ptr2;
            } else
                break;
        }
    }

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return got;

  err:
    for (i = 0; i < got; i++)
        VIR_FREE(names[i]);
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainPtr dom = NULL;
    int lpar_id = 0;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];

    lpar_id = phypGetLparID(session, managed_system, lpar_name, conn);
    if (lpar_id == -1)
        return NULL;

    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
        return NULL;

    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
}

static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];

    char *lpar_name = phypGetLparNAME(session, managed_system, lpar_id,
                                      conn);

    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
        goto err;

    if (exit_status < 0)
        goto err;

    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    VIR_FREE(lpar_name);
    return dom;

  err:
    VIR_FREE(lpar_name);
    return NULL;
}

static char *
phypDomainDumpXML(virDomainPtr dom, int flags)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;

    memset(&def, 0, sizeof(virDomainDef));

    def.virtType = VIR_DOMAIN_VIRT_PHYP;
    def.id = dom->id;

    char *lpar_name = phypGetLparNAME(session, managed_system, def.id,
                                      dom->conn);

    if (lpar_name == NULL) {
        VIR_ERROR("%s", "Unable to determine domain's name.");
        goto err;
    }

    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
        VIR_ERROR("%s", "Unable to generate random uuid.");
        goto err;
    }

    if ((def.maxmem =
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's max memory.");
        goto err;
    }

    if ((def.memory =
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's memory.");
        goto err;
    }

    if ((def.vcpus =
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's CPU.");
        goto err;
    }

    return virDomainDefFormat(&def, flags);

  err:
    return NULL;
}

static int
phypDomainResume(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "chsysstate -m %s -r lpar -o on --id %d -f %s",
         managed_system, dom->id, dom->name) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

static int
phypDomainShutdown(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "chsysstate -m %s -r lpar -o shutdown --id %d",
         managed_system, dom->id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;
}

static int
phypDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;

    info->state = phypGetLparState(dom->conn, dom->id);

    if ((info->maxMem =
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0)
        VIR_WARN("%s", "Unable to determine domain's max memory.");

    if ((info->memory =
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0)
        VIR_WARN("%s", "Unable to determine domain's memory.");

    if ((info->nrVirtCpu =
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        VIR_WARN("%s", "Unable to determine domain's CPU.");

    return 0;
}

static int
phypDomainDestroy(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "rmsyscfg -m %s -r lpar --id %d", managed_system, dom->id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
        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 ATTRIBUTE_UNUSED)
{

    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
    unsigned int i = 0;
    char *managed_system = phyp_driver->managed_system;

    if (!(def = virDomainDefParseString(phyp_driver->caps, xml,
                                        VIR_DOMAIN_XML_SECURE)))
        goto err;

    /* checking if this name already exists on this system */
    if (phypGetLparID(session, managed_system, def->name, conn) == -1) {
        VIR_WARN("%s", "LPAR name already exists.");
        goto err;
    }

    /* checking if ID or UUID already exists on this system */
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == def->id || lpars[i]->uuid == def->uuid) {
            VIR_WARN("%s", "LPAR ID or UUID already exists.");
            goto err;
        }
    }

    if ((dom = virGetDomain(conn, def->name, def->uuid)) == NULL)
        goto err;

    if (phypBuildLpar(conn, def) == -1)
        goto err;

    if (phypDomainResume(dom) == -1)
        goto err;

    return dom;

  err:
    virDomainDefFree(def);
    if (dom)
        virUnrefDomain(dom);
    return NULL;
}

static char *
phypConnectGetCapabilities(virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    char *xml;

    if ((xml = virCapabilitiesFormatXML(phyp_driver->caps)) == NULL)
        virReportOOMError();

    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)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;
    char operation;
    unsigned long ncpus = 0;
    unsigned int amount = 0;

    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        goto err;

    if (nvcpus > phypGetLparCPUMAX(dom)) {
        VIR_ERROR("%s",
                  "You are trying to set a number of CPUs bigger than "
                  "the max possible..");
        goto err;
    }

    if (ncpus > nvcpus) {
        operation = 'r';
        amount = nvcpus - ncpus;
    } else if (ncpus < nvcpus) {
        operation = 'a';
        amount = nvcpus - ncpus;
    } else
        goto exit;

    if (virAsprintf
        (&cmd,
         "chhwres -r proc -m %s --id %d -o %c --procunits %d 2>&1 |sed"
         "-e 's/^.*\\([0-9]\\+.[0-9]\\+\\).*$/\\1/g'",
         managed_system, dom->id, operation, amount) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0) {
        VIR_ERROR("%s",
                  "Possibly you don't have IBM Tools installed in your LPAR."
                  "Contact your support to enable this feature.");
        goto err;
    }

  exit:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

}

virDriver phypDriver = {
    VIR_DRV_PHYP,
    "PHYP",
    phypOpen,                   /* open */
    phypClose,                  /* close */
    NULL,                       /* supports_feature */
    NULL,                       /* type */
    NULL,                       /* version */
    NULL,                       /* libvirtVersion (impl. in libvirt.c) */
    NULL,                       /* getHostname */
    NULL,                       /* getMaxVcpus */
    NULL,                       /* nodeGetInfo */
    phypConnectGetCapabilities, /* getCapabilities */
    phypListDomains,            /* listDomains */
    phypNumDomains,             /* numOfDomains */
    phypDomainCreateAndStart,   /* domainCreateXML */
    phypDomainLookupByID,       /* domainLookupByID */
    NULL,                       /* domainLookupByUUID */
    phypDomainLookupByName,     /* domainLookupByName */
    NULL,                       /* domainSuspend */
    phypDomainResume,           /* domainResume */
    phypDomainShutdown,         /* domainShutdown */
    NULL,                       /* domainReboot */
    phypDomainDestroy,          /* domainDestroy */
    NULL,                       /* domainGetOSType */
    NULL,                       /* domainGetMaxMemory */
    NULL,                       /* domainSetMaxMemory */
    NULL,                       /* domainSetMemory */
    phypDomainGetInfo,          /* domainGetInfo */
    NULL,                       /* domainSave */
    NULL,                       /* domainRestore */
    NULL,                       /* domainCoreDump */
    phypDomainSetCPU,           /* domainSetVcpus */
    NULL,                       /* domainPinVcpu */
    NULL,                       /* domainGetVcpus */
    phypGetLparCPUMAX,          /* domainGetMaxVcpus */
    NULL,                       /* domainGetSecurityLabel */
    NULL,                       /* nodeGetSecurityModel */
    phypDomainDumpXML,          /* domainDumpXML */
    NULL,                       /* domainXMLFromNative */
    NULL,                       /* domainXMLToNative */
    phypListDefinedDomains,     /* listDefinedDomains */
    phypNumDefinedDomains,      /* numOfDefinedDomains */
    NULL,                       /* domainCreate */
    NULL,                       /* domainDefineXML */
    NULL,                       /* domainUndefine */
    NULL,                       /* domainAttachDevice */
    NULL,                       /* domainAttachDeviceFlags */
    NULL,                       /* domainDetachDevice */
    NULL,                       /* domainDetachDeviceFlags */
    NULL,                       /* domainUpdateDeviceFlags */
    NULL,                       /* domainGetAutostart */
    NULL,                       /* domainSetAutostart */
    NULL,                       /* domainGetSchedulerType */
    NULL,                       /* domainGetSchedulerParameters */
    NULL,                       /* domainSetSchedulerParameters */
    NULL,                       /* domainMigratePrepare */
    NULL,                       /* domainMigratePerform */
    NULL,                       /* domainMigrateFinish */
    NULL,                       /* domainBlockStats */
    NULL,                       /* domainInterfaceStats */
    NULL,                       /* domainMemoryStats */
    NULL,                       /* domainBlockPeek */
    NULL,                       /* domainMemoryPeek */
    NULL,                       /* domainGetBlockInfo */
    NULL,                       /* nodeGetCellsFreeMemory */
    NULL,                       /* getFreeMemory */
    NULL,                       /* domainEventRegister */
    NULL,                       /* domainEventDeregister */
    NULL,                       /* domainMigratePrepare2 */
    NULL,                       /* domainMigrateFinish2 */
    NULL,                       /* nodeDeviceDettach */
    NULL,                       /* nodeDeviceReAttach */
    NULL,                       /* nodeDeviceReset */
    NULL,                       /* domainMigratePrepareTunnel */
    phypIsEncrypted,            /* isEncrypted */
    phypIsSecure,               /* isSecure */
    NULL,                       /* domainIsActive */
    NULL,                       /* domainIsPersistent */
    NULL,                       /* cpuCompare */
    NULL,                       /* cpuBaseline */
    NULL, /* domainGetJobInfo */
    NULL, /* domainAbortJob */
    NULL, /* domainMigrateSetMaxDowntime */
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
    NULL, /* domainManagedSave */
    NULL, /* domainHasManagedSaveImage */
    NULL, /* domainManagedSaveRemove */
    NULL, /* domainSnapshotCreateXML */
    NULL, /* domainSnapshotDumpXML */
    NULL, /* domainSnapshotNum */
    NULL, /* domainSnapshotListNames */
    NULL, /* domainSnapshotLookupByName */
    NULL, /* domainHasCurrentSnapshot */
    NULL, /* domainSnapshotCurrent */
    NULL, /* domainRevertToSnapshot */
    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;
    char *managed_system = phyp_driver->managed_system;
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;

    if (virAsprintf
        (&cmd,
         "mksyscfg -m %s -r lpar -p %s -i min_mem=%d,desired_mem=%d,"
         "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s",
         managed_system, def->name, (int) def->memory,
         (int) def->memory, (int) def->maxmem, (int) def->vcpus,
         def->disks[0]->src) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0) {
        VIR_ERROR("%s\"%s\"", "Unable to create LPAR. Reason: ", ret);
        goto err;
    }

    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
        VIR_ERROR("%s", "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_WARN("%s", "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_WARN("%s",
                         "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_WARN("%s",
                         "Unable to read information to local file.");
                goto err;
            }
        }
    } else
        virReportOOMError();<commit_msg>maint: use VIR_WARN0("...") rather than VIR_WARN("%s", "...")<commit_after>
/*
 * Copyright (C) 2010 Red Hat, Inc.
 * Copyright IBM Corp. 2009
 *
 * phyp_driver.c: ssh layer to access Power Hypervisors
 *
 * Authors:
 *  <NAME> <otubo at linux.vnet.ibm.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <libssh2.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <domain_event.h>

#include "internal.h"
#include "authhelper.h"
#include "util.h"
#include "datatypes.h"
#include "buf.h"
#include "memory.h"
#include "logging.h"
#include "driver.h"
#include "libvirt/libvirt.h"
#include "virterror_internal.h"
#include "uuid.h"
#include "domain_conf.h"
#include "nodeinfo.h"

#include "phyp_driver.h"

#define VIR_FROM_THIS VIR_FROM_PHYP

#define PHYP_ERROR(code, ...)                                                 \
    virReportErrorHelper(NULL, VIR_FROM_PHYP, code, __FILE__, __FUNCTION__,   \
                         __LINE__, __VA_ARGS__)

/*
 * URI: phyp://user@[hmc|ivm]/managed_system
 * */

static virDrvOpenStatus
phypOpen(virConnectPtr conn,
         virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
{
    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;

    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 (conn->uri->path == NULL) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("Missing managed system name in phyp:// URI"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (VIR_ALLOC(phyp_driver) < 0) {
        virReportOOMError();
        goto failure;
    }

    if (VIR_ALLOC(uuid_table) < 0) {
        virReportOOMError();
        goto failure;
    }

    if (VIR_ALLOC(connection_data) < 0) {
        virReportOOMError();
        goto failure;
    }

    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;

    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 (phypUUIDTable_Init(conn) == -1)
        goto failure;

    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;
}

static int
phypClose(virConnectPtr conn)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;

    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);

    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 *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
               int *internal_socket)
{
    LIBSSH2_SESSION *session;
    const char *hostname = conn->uri->server;
    char *username = NULL;
    char *password = NULL;
    int sock;
    int rc;
    struct addrinfo *ai = NULL, *cur;
    struct addrinfo hints;
    int ret;
    char *pubkey = NULL;
    char *pvtkey = NULL;
    char *userhome = virGetUserDirectory(geteuid());
    struct stat pvt_stat, pub_stat;

    if (userhome == NULL)
        goto err;

    if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0) {
        virReportOOMError();
        goto err;
    }

    if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0) {
        virReportOOMError();
        goto err;
    }

    if (conn->uri->user != NULL) {
        username = strdup(conn->uri->user);

        if (username == NULL) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (auth == NULL || auth->cb == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("No authentication callback provided."));
            goto err;
        }

        username = virRequestUsername(auth, NULL, conn->uri->server);

        if (username == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
            goto err;
        }
    }

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    ret = getaddrinfo(hostname, "22", &hints, &ai);
    if (ret != 0) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Error while getting %s address info"), hostname);
        goto err;
    }

    cur = ai;
    while (cur != NULL) {
        sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
        if (sock >= 0) {
            if (connect(sock, cur->ai_addr, cur->ai_addrlen) == 0) {
                goto connected;
            }
            close(sock);
        }
        cur = cur->ai_next;
    }

    PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
               _("Failed to connect to %s"), hostname);
    freeaddrinfo(ai);
    goto err;

  connected:

    (*internal_socket) = sock;

    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
        goto err;

    /* tell libssh2 we want it all done non-blocking */
    libssh2_session_set_blocking(session, 0);

    while ((rc = libssh2_session_startup(session, sock)) ==
           LIBSSH2_ERROR_EAGAIN) ;
    if (rc) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("Failure establishing SSH session."));
        goto disconnect;
    }

    /* Trying authentication by pubkey */
    if (stat(pvtkey, &pvt_stat) || stat(pubkey, &pub_stat)) {
        rc = LIBSSH2_ERROR_SOCKET_NONE;
        goto keyboard_interactive;
    }

    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
           LIBSSH2_ERROR_EAGAIN) ;

  keyboard_interactive:
    if (rc == LIBSSH2_ERROR_SOCKET_NONE
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
        if (auth == NULL || auth->cb == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("No authentication callback provided."));
            goto disconnect;
        }

        password = <PASSWORD>(auth, username, conn->uri->server);

        if (password == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
            goto disconnect;
        }

        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
               LIBSSH2_ERROR_EAGAIN) ;

        if (rc) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("Authentication failed"));
            goto disconnect;
        } else
            goto exit;

    } else if (rc == LIBSSH2_ERROR_NONE) {
        goto exit;

    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
        goto err;
    }

  disconnect:
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
  err:
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return NULL;

  exit:
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    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)
{
    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 (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);
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&tex_ret);
}

/* return the lpar_id given a name and a managed system name */
static int
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
{
    int exit_status = 0;
    int lpar_id = 0;
    char *char_ptr;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s --filter lpar_names=%s -F lpar_id",
                    managed_system, name) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    if (virStrToLong_i(ret, &char_ptr, 10, &lpar_id) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return lpar_id;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

/* return the lpar name given a lpar_id and a managed system name */
static char *
phypGetLparNAME(LIBSSH2_SESSION * session, const char *managed_system,
                unsigned int lpar_id, virConnectPtr conn)
{
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F name",
                    managed_system, lpar_id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char *char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    VIR_FREE(cmd);
    return ret;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return NULL;
}


/* Search into the uuid_table for a lpar_uuid given a lpar_id
 * and a managed system name
 *
 * return:  0 - record found
 *         -1 - not found
 * */
int
phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
    unsigned int i = 0;

    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
            memmove(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
            return 0;
        }
    }

    return -1;
}

/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int memory = 0;
    int exit_status = 0;

    if (type != 1 && type != 0)
        goto err;

    if (type) {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r mem --level lpar -F curr_mem "
                        "--filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r mem --level lpar -F "
                        "curr_max_mem --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &memory) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return memory;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

}

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
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int exit_status = 0;
    int vcpus = 0;

    if (type) {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r proc --level lpar -F "
                        "curr_max_procs --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    } else {
        if (virAsprintf(&cmd,
                        "lshwres -m %s -r proc --level lpar -F "
                        "curr_procs --filter lpar_ids=%d",
                        managed_system, lpar_id) < 0) {
            virReportOOMError();
            goto err;
        }
    }
    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &vcpus) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return (unsigned long) vcpus;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;
}

int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    char *char_ptr;
    int remote_slot = 0;
    int exit_status = 0;

    if (virAsprintf(&cmd,
                    "lshwres -m %s -r virtualio --rsubtype scsi -F "
                    "remote_slot_num --filter lpar_names=%s",
                    managed_system, lpar_name) < 0) {
        virReportOOMError();
        goto err;
    }
    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (virStrToLong_i(ret, &char_ptr, 10, &remote_slot) == -1)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return remote_slot;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

char *
phypGetBackingDevice(virConnectPtr conn, const char *managed_system,
                     char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    int remote_slot = 0;
    int exit_status = 0;
    char *char_ptr;
    char *backing_device = NULL;

    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        goto err;

    if (virAsprintf(&cmd,
                    "lshwres -m %s -r virtualio --rsubtype scsi -F "
                    "backing_devices --filter slots=%d",
                    managed_system, remote_slot) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto err;

    /* here is a little trick to deal returns of this kind:
     *
     * 0x8100000000000000//lv01
     *
     * the information we really need is only lv01, so we
     * need to skip a lot of things on the string.
     * */
    char_ptr = strchr(ret, '/');

    if (char_ptr) {
        char_ptr++;
        if (char_ptr[0] == '/')
            char_ptr++;
        else
            goto err;

        backing_device = strdup(char_ptr);

        if (backing_device == NULL) {
            virReportOOMError();
            goto err;
        }
    } else {
        backing_device = ret;
        ret = NULL;
    }

    char_ptr = strchr(backing_device, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return backing_device;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return NULL;

}

int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
{
    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;
    char *char_ptr = NULL;
    char *managed_system = phyp_driver->managed_system;
    int state = VIR_DOMAIN_NOSTATE;

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s -F state --filter lpar_ids=%d",
                    managed_system, lpar_id) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto cleanup;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (STREQ(ret, "Running"))
        state = VIR_DOMAIN_RUNNING;
    else if (STREQ(ret, "Not Activated"))
        state = VIR_DOMAIN_SHUTOFF;
    else if (STREQ(ret, "Shutting Down"))
        state = VIR_DOMAIN_SHUTDOWN;

  cleanup:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return state;
}

int
phypGetVIOSPartitionID(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;
    int id = -1;
    char *char_ptr;
    char *managed_system = phyp_driver->managed_system;

    if (virAsprintf(&cmd,
                    "lssyscfg -m %s -r lpar -F lpar_id,lpar_env|grep "
                    "vioserver|sed -s 's/,.*$//g'", managed_system) < 0) {
        virReportOOMError();
        goto err;
    }

    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
phypDiskType(virConnectPtr conn, char *backing_device)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;
    char *char_ptr;
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    int disk_type = -1;

    if (virAsprintf(&cmd,
                    "viosvrcmd -m %s -p %d -c \"lssp -field name type "
                    "-fmt , -all|grep %s|sed -e 's/^.*,//g'\"",
                    managed_system, vios_id, backing_device) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0 || ret == NULL)
        goto cleanup;

    char_ptr = strchr(ret, '\n');

    if (char_ptr)
        *char_ptr = '\0';

    if (STREQ(ret, "LVPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_BLOCK;
    else if (STREQ(ret, "FBPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_FILE;

  cleanup:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    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 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;

    if (type == 0)
        state = "|grep Running";
    else if (type == 1)
        state = "|grep \"Not Activated\"";
    else
        state = " ";

    if (virAsprintf(&cmd,
                    "lssyscfg -r lpar -m %s -F lpar_id,state %s |grep -c "
                    "^[0-9]*", managed_system, state) < 0) {
        virReportOOMError();
        goto err;
    }

    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)
{
    return phypNumDomainsGeneric(conn, 1);
}

static int
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;
    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;

    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

    memset(id_c, 0, 10);

    if (virAsprintf
        (&cmd,
         "lssyscfg -r lpar -m %s -F lpar_id,state %s | sed -e 's/,.*$//g'",
         managed_system, state) < 0) {
        virReportOOMError();
        goto err;
    }
    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)
{
    return phypListDomainsGeneric(conn, ids, nids, 0);
}

static int
phypListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    int got = 0;
    int i;
    char *cmd = NULL;
    char *ret = NULL;
    char *domains = NULL;
    char *char_ptr2 = NULL;

    if (virAsprintf
        (&cmd,
         "lssyscfg -r lpar -m %s -F name,state | grep \"Not Activated\" | "
         "sed -e 's/,.*$//g'", managed_system) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    /* I need to parse the textual return in order to get the domains */
    if (exit_status < 0 || ret == NULL)
        goto err;
    else {
        domains = ret;

        while (got < nnames) {
            char_ptr2 = strchr(domains, '\n');

            if (char_ptr2) {
                *char_ptr2 = '\0';
                if ((names[got++] = strdup(domains)) == NULL) {
                    virReportOOMError();
                    goto err;
                }
                char_ptr2++;
                domains = char_ptr2;
            } else
                break;
        }
    }

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return got;

  err:
    for (i = 0; i < got; i++)
        VIR_FREE(names[i]);
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainPtr dom = NULL;
    int lpar_id = 0;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];

    lpar_id = phypGetLparID(session, managed_system, lpar_name, conn);
    if (lpar_id == -1)
        return NULL;

    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
        return NULL;

    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
}

static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];

    char *lpar_name = phypGetLparNAME(session, managed_system, lpar_id,
                                      conn);

    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
        goto err;

    if (exit_status < 0)
        goto err;

    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    VIR_FREE(lpar_name);
    return dom;

  err:
    VIR_FREE(lpar_name);
    return NULL;
}

static char *
phypDomainDumpXML(virDomainPtr dom, int flags)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;

    memset(&def, 0, sizeof(virDomainDef));

    def.virtType = VIR_DOMAIN_VIRT_PHYP;
    def.id = dom->id;

    char *lpar_name = phypGetLparNAME(session, managed_system, def.id,
                                      dom->conn);

    if (lpar_name == NULL) {
        VIR_ERROR("%s", "Unable to determine domain's name.");
        goto err;
    }

    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
        VIR_ERROR("%s", "Unable to generate random uuid.");
        goto err;
    }

    if ((def.maxmem =
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's max memory.");
        goto err;
    }

    if ((def.memory =
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's memory.");
        goto err;
    }

    if ((def.vcpus =
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
        VIR_ERROR("%s", "Unable to determine domain's CPU.");
        goto err;
    }

    return virDomainDefFormat(&def, flags);

  err:
    return NULL;
}

static int
phypDomainResume(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "chsysstate -m %s -r lpar -o on --id %d -f %s",
         managed_system, dom->id, dom->name) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return -1;
}

static int
phypDomainShutdown(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "chsysstate -m %s -r lpar -o shutdown --id %d",
         managed_system, dom->id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;
}

static int
phypDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;

    info->state = phypGetLparState(dom->conn, dom->id);

    if ((info->maxMem =
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0)
        VIR_WARN0("Unable to determine domain's max memory.");

    if ((info->memory =
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0)
        VIR_WARN0("Unable to determine domain's memory.");

    if ((info->nrVirtCpu =
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        VIR_WARN0("Unable to determine domain's CPU.");

    return 0;
}

static int
phypDomainDestroy(virDomainPtr dom)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;

    if (virAsprintf
        (&cmd,
         "rmsyscfg -m %s -r lpar --id %d", managed_system, dom->id) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0)
        goto err;

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
        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 ATTRIBUTE_UNUSED)
{

    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
    unsigned int i = 0;
    char *managed_system = phyp_driver->managed_system;

    if (!(def = virDomainDefParseString(phyp_driver->caps, xml,
                                        VIR_DOMAIN_XML_SECURE)))
        goto err;

    /* checking if this name already exists on this system */
    if (phypGetLparID(session, managed_system, def->name, conn) == -1) {
        VIR_WARN0("LPAR name already exists.");
        goto err;
    }

    /* checking if ID or UUID already exists on this system */
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == def->id || lpars[i]->uuid == def->uuid) {
            VIR_WARN0("LPAR ID or UUID already exists.");
            goto err;
        }
    }

    if ((dom = virGetDomain(conn, def->name, def->uuid)) == NULL)
        goto err;

    if (phypBuildLpar(conn, def) == -1)
        goto err;

    if (phypDomainResume(dom) == -1)
        goto err;

    return dom;

  err:
    virDomainDefFree(def);
    if (dom)
        virUnrefDomain(dom);
    return NULL;
}

static char *
phypConnectGetCapabilities(virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
    char *xml;

    if ((xml = virCapabilitiesFormatXML(phyp_driver->caps)) == NULL)
        virReportOOMError();

    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)
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *cmd = NULL;
    char *ret = NULL;
    char operation;
    unsigned long ncpus = 0;
    unsigned int amount = 0;

    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        goto err;

    if (nvcpus > phypGetLparCPUMAX(dom)) {
        VIR_ERROR("%s",
                  "You are trying to set a number of CPUs bigger than "
                  "the max possible..");
        goto err;
    }

    if (ncpus > nvcpus) {
        operation = 'r';
        amount = nvcpus - ncpus;
    } else if (ncpus < nvcpus) {
        operation = 'a';
        amount = nvcpus - ncpus;
    } else
        goto exit;

    if (virAsprintf
        (&cmd,
         "chhwres -r proc -m %s --id %d -o %c --procunits %d 2>&1 |sed"
         "-e 's/^.*\\([0-9]\\+.[0-9]\\+\\).*$/\\1/g'",
         managed_system, dom->id, operation, amount) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, dom->conn);

    if (exit_status < 0) {
        VIR_ERROR("%s",
                  "Possibly you don't have IBM Tools installed in your LPAR."
                  "Contact your support to enable this feature.");
        goto err;
    }

  exit:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

  err:
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return 0;

}

virDriver phypDriver = {
    VIR_DRV_PHYP,
    "PHYP",
    phypOpen,                   /* open */
    phypClose,                  /* close */
    NULL,                       /* supports_feature */
    NULL,                       /* type */
    NULL,                       /* version */
    NULL,                       /* libvirtVersion (impl. in libvirt.c) */
    NULL,                       /* getHostname */
    NULL,                       /* getMaxVcpus */
    NULL,                       /* nodeGetInfo */
    phypConnectGetCapabilities, /* getCapabilities */
    phypListDomains,            /* listDomains */
    phypNumDomains,             /* numOfDomains */
    phypDomainCreateAndStart,   /* domainCreateXML */
    phypDomainLookupByID,       /* domainLookupByID */
    NULL,                       /* domainLookupByUUID */
    phypDomainLookupByName,     /* domainLookupByName */
    NULL,                       /* domainSuspend */
    phypDomainResume,           /* domainResume */
    phypDomainShutdown,         /* domainShutdown */
    NULL,                       /* domainReboot */
    phypDomainDestroy,          /* domainDestroy */
    NULL,                       /* domainGetOSType */
    NULL,                       /* domainGetMaxMemory */
    NULL,                       /* domainSetMaxMemory */
    NULL,                       /* domainSetMemory */
    phypDomainGetInfo,          /* domainGetInfo */
    NULL,                       /* domainSave */
    NULL,                       /* domainRestore */
    NULL,                       /* domainCoreDump */
    phypDomainSetCPU,           /* domainSetVcpus */
    NULL,                       /* domainPinVcpu */
    NULL,                       /* domainGetVcpus */
    phypGetLparCPUMAX,          /* domainGetMaxVcpus */
    NULL,                       /* domainGetSecurityLabel */
    NULL,                       /* nodeGetSecurityModel */
    phypDomainDumpXML,          /* domainDumpXML */
    NULL,                       /* domainXMLFromNative */
    NULL,                       /* domainXMLToNative */
    phypListDefinedDomains,     /* listDefinedDomains */
    phypNumDefinedDomains,      /* numOfDefinedDomains */
    NULL,                       /* domainCreate */
    NULL,                       /* domainDefineXML */
    NULL,                       /* domainUndefine */
    NULL,                       /* domainAttachDevice */
    NULL,                       /* domainAttachDeviceFlags */
    NULL,                       /* domainDetachDevice */
    NULL,                       /* domainDetachDeviceFlags */
    NULL,                       /* domainUpdateDeviceFlags */
    NULL,                       /* domainGetAutostart */
    NULL,                       /* domainSetAutostart */
    NULL,                       /* domainGetSchedulerType */
    NULL,                       /* domainGetSchedulerParameters */
    NULL,                       /* domainSetSchedulerParameters */
    NULL,                       /* domainMigratePrepare */
    NULL,                       /* domainMigratePerform */
    NULL,                       /* domainMigrateFinish */
    NULL,                       /* domainBlockStats */
    NULL,                       /* domainInterfaceStats */
    NULL,                       /* domainMemoryStats */
    NULL,                       /* domainBlockPeek */
    NULL,                       /* domainMemoryPeek */
    NULL,                       /* domainGetBlockInfo */
    NULL,                       /* nodeGetCellsFreeMemory */
    NULL,                       /* getFreeMemory */
    NULL,                       /* domainEventRegister */
    NULL,                       /* domainEventDeregister */
    NULL,                       /* domainMigratePrepare2 */
    NULL,                       /* domainMigrateFinish2 */
    NULL,                       /* nodeDeviceDettach */
    NULL,                       /* nodeDeviceReAttach */
    NULL,                       /* nodeDeviceReset */
    NULL,                       /* domainMigratePrepareTunnel */
    phypIsEncrypted,            /* isEncrypted */
    phypIsSecure,               /* isSecure */
    NULL,                       /* domainIsActive */
    NULL,                       /* domainIsPersistent */
    NULL,                       /* cpuCompare */
    NULL,                       /* cpuBaseline */
    NULL, /* domainGetJobInfo */
    NULL, /* domainAbortJob */
    NULL, /* domainMigrateSetMaxDowntime */
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
    NULL, /* domainManagedSave */
    NULL, /* domainHasManagedSaveImage */
    NULL, /* domainManagedSaveRemove */
    NULL, /* domainSnapshotCreateXML */
    NULL, /* domainSnapshotDumpXML */
    NULL, /* domainSnapshotNum */
    NULL, /* domainSnapshotListNames */
    NULL, /* domainSnapshotLookupByName */
    NULL, /* domainHasCurrentSnapshot */
    NULL, /* domainSnapshotCurrent */
    NULL, /* domainRevertToSnapshot */
    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;
    char *managed_system = phyp_driver->managed_system;
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;

    if (virAsprintf
        (&cmd,
         "mksyscfg -m %s -r lpar -p %s -i min_mem=%d,desired_mem=%d,"
         "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s",
         managed_system, def->name, (int) def->memory,
         (int) def->memory, (int) def->maxmem, (int) def->vcpus,
         def->disks[0]->src) < 0) {
        virReportOOMError();
        goto err;
    }

    ret = phypExec(session, cmd, &exit_status, conn);

    if (exit_status < 0) {
        VIR_ERROR("%s\"%s\"", "Unable to create LPAR. Reason: ", ret);
        goto err;
    }

    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
        VIR_ERROR("%s", "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_WARN("%s",
                         "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_WARN("%s",
                         "Unable to read information to local file.");
                goto err;
            }
        }
    } else
        virReportOOMError();
{'fraction_non_alphanumeric': 0.11593303771205403, 'fraction_numerical': 0.007861763150400715, 'mean_word_length': 2.0423280423280423, 'pattern_counts': {'":': 0, '<': 157, '<?xml version=': 0, '>': 537, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 44, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5769905', 'n_tokens_mistral': 33032, 'n_tokens_neox': 31645, 'n_words': 7547}