phyp_driver.c 108.8 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2012 Red Hat, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * Copyright IBM Corp. 2009
 *
 * phyp_driver.c: ssh layer to access Power Hypervisors
 *
 * Authors:
 *  Eduardo Otubo <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>
28
#include <sys/stat.h>
29 30 31 32 33 34 35 36
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
37 38 39 40 41
#include <libssh2.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
42 43 44
#include <fcntl.h>
#include <sys/utsname.h>
#include <domain_event.h>
45 46

#include "internal.h"
47
#include "virauth.h"
48 49 50 51 52 53 54 55 56 57
#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"
58
#include "storage_conf.h"
59
#include "nodeinfo.h"
E
Eric Blake 已提交
60
#include "virfile.h"
E
Eduardo Otubo 已提交
61
#include "interface_conf.h"
62 63 64 65 66

#include "phyp_driver.h"

#define VIR_FROM_THIS VIR_FROM_PHYP

67
#define PHYP_ERROR(code, ...)                                                 \
68
    virReportErrorHelper(VIR_FROM_PHYP, code, __FILE__, __FUNCTION__,         \
69
                         __LINE__, __VA_ARGS__)
70

71 72 73 74
/*
 * URI: phyp://user@[hmc|ivm]/managed_system
 * */

75 76
static unsigned const int HMC = 0;
static unsigned const int IVM = 127;
E
Eduardo Otubo 已提交
77 78
static unsigned const int PHYP_IFACENAME_SIZE = 24;
static unsigned const int PHYP_MAC_SIZE= 12;
79

80 81 82 83 84 85 86 87 88
static int
waitsocket(int socket_fd, LIBSSH2_SESSION * session)
{
    struct timeval timeout;
    int rc;
    fd_set fd;
    fd_set *writefd = NULL;
    fd_set *readfd = NULL;
    int dir;
89

90 91
    timeout.tv_sec = 0;
    timeout.tv_usec = 1000;
92

93
    FD_ZERO(&fd);
94

95
    FD_SET(socket_fd, &fd);
96

97 98
    /* now make sure we wait in the correct direction */
    dir = libssh2_session_block_directions(session);
99

100 101
    if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
        readfd = &fd;
102

103 104
    if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
        writefd = &fd;
105

106
    rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
107

108 109
    return rc;
}
110

111 112
/* this function is the layer that manipulates the ssh channel itself
 * and executes the commands on the remote machine */
113 114 115
static char *phypExec(LIBSSH2_SESSION *, const char *, int *, virConnectPtr)
    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
    ATTRIBUTE_NONNULL(4);
116
static char *
117
phypExec(LIBSSH2_SESSION *session, const char *cmd, int *exit_status,
118 119 120 121 122
         virConnectPtr conn)
{
    LIBSSH2_CHANNEL *channel;
    ConnectionData *connection_data = conn->networkPrivateData;
    virBuffer tex_ret = VIR_BUFFER_INITIALIZER;
123 124
    char *buffer = NULL;
    size_t buffer_size = 16384;
125 126 127 128
    int exitcode;
    int bytecount = 0;
    int sock = connection_data->sock;
    int rc = 0;
129

130 131 132 133 134
    if (VIR_ALLOC_N(buffer, buffer_size) < 0) {
        virReportOOMError();
        return NULL;
    }

135 136 137 138 139
    /* 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);
140 141
    }

142 143
    if (channel == NULL) {
        goto err;
144
    }
145

146 147 148
    while ((rc = libssh2_channel_exec(channel, cmd)) ==
           LIBSSH2_ERROR_EAGAIN) {
        waitsocket(sock, session);
149
    }
150

151 152 153
    if (rc != 0) {
        goto err;
    }
154

155 156 157
    for (;;) {
        /* loop until we block */
        do {
158
            rc = libssh2_channel_read(channel, buffer, buffer_size);
159 160
            if (rc > 0) {
                bytecount += rc;
161
                virBufferAdd(&tex_ret, buffer, -1);
162 163 164
            }
        }
        while (rc > 0);
165

166 167 168 169 170 171 172
        /* 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;
        }
E
Eduardo Otubo 已提交
173 174
    }

175
    exitcode = 127;
176

177 178
    while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) {
        waitsocket(sock, session);
179 180
    }

181 182
    if (rc == 0) {
        exitcode = libssh2_channel_get_exit_status(channel);
183 184
    }

185 186 187
    (*exit_status) = exitcode;
    libssh2_channel_free(channel);
    channel = NULL;
188 189
    VIR_FREE(buffer);

190 191 192 193 194 195
    if (virBufferError(&tex_ret)) {
        virBufferFreeAndReset(&tex_ret);
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&tex_ret);
196 197 198 199 200 201

err:
    (*exit_status) = SSH_CMD_ERR;
    virBufferFreeAndReset(&tex_ret);
    VIR_FREE(buffer);
    return NULL;
202 203
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
/* Convenience wrapper function */
static char *phypExecBuffer(LIBSSH2_SESSION *, virBufferPtr buf, int *,
                            virConnectPtr, bool) ATTRIBUTE_NONNULL(1)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
static char *
phypExecBuffer(LIBSSH2_SESSION *session, virBufferPtr buf, int *exit_status,
               virConnectPtr conn, bool strip_newline)
{
    char *cmd;
    char *ret;

    if (virBufferError(buf)) {
        virBufferFreeAndReset(buf);
        virReportOOMError();
        return NULL;
    }
    cmd = virBufferContentAndReset(buf);
    ret = phypExec(session, cmd, exit_status, conn);
    VIR_FREE(cmd);
    if (ret && *exit_status == 0 && strip_newline) {
        char *nl = strchr(ret, '\n');
        if (nl)
            *nl = '\0';
    }
    return ret;
}

E
Eric Blake 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
/* Convenience wrapper function */
static int phypExecInt(LIBSSH2_SESSION *, virBufferPtr, virConnectPtr, int *)
    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
static int
phypExecInt(LIBSSH2_SESSION *session, virBufferPtr buf, virConnectPtr conn,
            int *result)
{
    char *str;
    int ret;
    char *char_ptr;

    str = phypExecBuffer(session, buf, &ret, conn, true);
    if (!str || ret) {
        VIR_FREE(str);
        return -1;
    }
    ret = virStrToLong_i(str, &char_ptr, 10, result);
    if (ret == 0 && *char_ptr)
        VIR_WARN("ignoring suffix during integer parsing of '%s'", str);
    VIR_FREE(str);
    return ret;
}

254
static int
255
phypGetSystemType(virConnectPtr conn)
256 257
{
    ConnectionData *connection_data = conn->networkPrivateData;
258
    LIBSSH2_SESSION *session = connection_data->session;
259 260 261
    char *cmd = NULL;
    char *ret = NULL;
    int exit_status = 0;
262

263 264
    if (virAsprintf(&cmd, "lshmc -V") < 0) {
        virReportOOMError();
265
        return -1;
266 267
    }
    ret = phypExec(session, cmd, &exit_status, conn);
268

269 270 271
    VIR_FREE(cmd);
    VIR_FREE(ret);
    return exit_status;
272 273
}

274
static int
275
phypGetVIOSPartitionID(virConnectPtr conn)
276
{
277 278 279 280 281 282 283
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    int id = -1;
    char *managed_system = phyp_driver->managed_system;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
284

285 286
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
287
        virBufferAsprintf(&buf, " -m %s", managed_system);
E
Eric Blake 已提交
288 289
    virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env"
                    "|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'");
E
Eric Blake 已提交
290
    phypExecInt(session, &buf, conn, &id);
291
    return id;
292
}
293

294 295 296 297 298 299 300

static int phypDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED)
{
    return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
}


301 302 303 304 305 306
static virCapsPtr
phypCapsInit(void)
{
    struct utsname utsname;
    virCapsPtr caps;
    virCapsGuestPtr guest;
307

308
    uname(&utsname);
309

310 311
    if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL)
        goto no_memory;
312

313 314 315 316 317 318
    /* 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);
319
        VIR_WARN
320
            ("Failed to query host NUMA topology, disabling NUMA capabilities");
321 322
    }

323 324 325
    /* XXX shouldn't 'borrow' KVM's prefix */
    virCapabilitiesSetMacPrefix(caps, (unsigned char[]) {
                                0x52, 0x54, 0x00});
326

327 328 329 330 331 332
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "linux",
                                         utsname.machine,
                                         sizeof(int) == 4 ? 32 : 8,
                                         NULL, NULL, 0, NULL)) == NULL)
        goto no_memory;
333

334 335 336
    if (virCapabilitiesAddGuestDomain(guest,
                                      "phyp", NULL, NULL, 0, NULL) == NULL)
        goto no_memory;
337

338 339
    caps->defaultConsoleTargetType = phypDefaultConsoleType;

340
    return caps;
341

342
no_memory:
343 344 345
    virCapabilitiesFree(caps);
    return NULL;
}
346

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
/* This is a generic function that won't be used directly by
 * libvirt api. The function returns the number of domains
 * in different states: Running, Not Activated and all:
 *
 * type: 0 - Running
 *       1 - Not Activated
 *       * - All
 * */
static int
phypNumDomainsGeneric(virConnectPtr conn, unsigned int type)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
362
    int ndom = -1;
363 364 365
    char *managed_system = phyp_driver->managed_system;
    const char *state;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
366

367 368 369 370 371 372 373
    if (type == 0)
        state = "|grep Running";
    else if (type == 1) {
        if (system_type == HMC) {
            state = "|grep \"Not Activated\"";
        } else {
            state = "|grep \"Open Firmware\"";
374
        }
375 376
    } else
        state = " ";
377

378 379
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
380 381
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9][0-9]*'",
382
                      state);
E
Eric Blake 已提交
383
    phypExecInt(session, &buf, conn, &ndom);
384
    return ndom;
385 386
}

387 388 389 390 391 392 393 394 395 396
/* 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)
397
{
398
    ConnectionData *connection_data = conn->networkPrivateData;
E
Eduardo Otubo 已提交
399
    phyp_driverPtr phyp_driver = conn->privateData;
400
    LIBSSH2_SESSION *session = connection_data->session;
E
Eduardo Otubo 已提交
401
    int system_type = phyp_driver->system_type;
402
    char *managed_system = phyp_driver->managed_system;
403
    int exit_status = 0;
404
    int got = -1;
405
    char *ret = NULL;
406
    char *line, *next_line;
407
    const char *state;
E
Eduardo Otubo 已提交
408 409
    virBuffer buf = VIR_BUFFER_INITIALIZER;

410 411 412 413 414
    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

E
Eduardo Otubo 已提交
415 416
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
417 418
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'",
419
                      state);
420
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
421

422
    if (exit_status < 0 || ret == NULL)
423
        goto cleanup;
424 425 426 427 428 429 430 431

    /* I need to parse the textual return in order to get the ids */
    line = ret;
    got = 0;
    while (*line && got < nids) {
        if (virStrToLong_i(line, &next_line, 10, &ids[got]) == -1) {
            VIR_ERROR(_("Cannot parse number from '%s'"), line);
            got = -1;
432
            goto cleanup;
433
        }
434 435 436 437
        got++;
        line = next_line;
        while (*line == '\n')
            line++; /* skip \n */
438
    }
439

440
cleanup:
441
    VIR_FREE(ret);
442
    return got;
443 444
}

445 446
static int
phypUUIDTable_WriteFile(virConnectPtr conn)
447
{
448 449
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
450
    unsigned int i = 0;
451 452 453 454 455
    int fd = -1;
    char local_file[] = "./uuid_table";

    if ((fd = creat(local_file, 0755)) == -1)
        goto err;
456

457
    for (i = 0; i < uuid_table->nlpars; i++) {
458 459 460
        if (safewrite(fd, &uuid_table->lpars[i]->id,
                      sizeof(uuid_table->lpars[i]->id)) !=
            sizeof(uuid_table->lpars[i]->id)) {
461
            VIR_ERROR(_("Unable to write information to local file."));
462 463 464 465 466
            goto err;
        }

        if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) !=
            VIR_UUID_BUFLEN) {
467
            VIR_ERROR(_("Unable to write information to local file."));
468
            goto err;
469 470 471
        }
    }

472 473 474 475 476
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
        goto err;
    }
477 478
    return 0;

479
err:
480
    VIR_FORCE_CLOSE(fd);
481 482 483
    return -1;
}

484 485
static int
phypUUIDTable_Push(virConnectPtr conn)
486 487
{
    ConnectionData *connection_data = conn->networkPrivateData;
488
    LIBSSH2_SESSION *session = connection_data->session;
489 490 491 492 493
    LIBSSH2_CHANNEL *channel = NULL;
    virBuffer username = VIR_BUFFER_INITIALIZER;
    struct stat local_fileinfo;
    char buffer[1024];
    int rc = 0;
494
    FILE *fd = NULL;
495 496 497 498
    size_t nread, sent;
    char *ptr;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
499

500
    if (conn->uri->user != NULL) {
501
        virBufferAdd(&username, conn->uri->user, -1);
E
Eduardo Otubo 已提交
502

503 504 505 506 507 508 509 510 511 512 513
        if (virBufferError(&username)) {
            virBufferFreeAndReset(&username);
            virReportOOMError();
            goto err;
        }
    }

    if (virAsprintf
        (&remote_file, "/home/%s/libvirt_uuid_table",
         virBufferContentAndReset(&username))
        < 0) {
E
Eduardo Otubo 已提交
514
        virReportOOMError();
515
        goto err;
516 517
    }

518
    if (stat(local_file, &local_fileinfo) == -1) {
519
        VIR_WARN("Unable to stat local file.");
520 521
        goto err;
    }
522

523
    if (!(fd = fopen(local_file, "rb"))) {
524
        VIR_WARN("Unable to open local file.");
525
        goto err;
526
    }
527

528 529 530 531 532
    do {
        channel =
            libssh2_scp_send(session, remote_file,
                             0x1FF & local_fileinfo.st_mode,
                             (unsigned long) local_fileinfo.st_size);
533

534 535 536 537
        if ((!channel) && (libssh2_session_last_errno(session) !=
                           LIBSSH2_ERROR_EAGAIN))
            goto err;
    } while (!channel);
538

539 540 541 542 543 544 545 546 547 548 549 550 551
    do {
        nread = fread(buffer, 1, sizeof(buffer), fd);
        if (nread <= 0) {
            if (feof(fd)) {
                /* end of file */
                break;
            } else {
                VIR_ERROR(_("Failed to read from %s"), local_file);
                goto err;
            }
        }
        ptr = buffer;
        sent = 0;
552

553 554 555 556 557 558 559 560 561 562 563 564 565
        do {
            /* write the same data over and over, until error or completion */
            rc = libssh2_channel_write(channel, ptr, nread);
            if (LIBSSH2_ERROR_EAGAIN == rc) {   /* must loop around */
                continue;
            } else if (rc > 0) {
                /* rc indicates how many bytes were written this time */
                sent += rc;
            }
            ptr += sent;
            nread -= sent;
        } while (rc > 0 && sent < nread);
    } while (1);
566

567 568 569 570 571 572 573 574
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
    virBufferFreeAndReset(&username);
575 576
    return 0;

577
err:
578 579 580 581 582 583 584
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
585
    VIR_FORCE_FCLOSE(fd);
586
    return -1;
587 588 589
}

static int
590
phypUUIDTable_RemLpar(virConnectPtr conn, int id)
591
{
E
Eduardo Otubo 已提交
592
    phyp_driverPtr phyp_driver = conn->privateData;
593 594
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    unsigned int i = 0;
E
Eduardo Otubo 已提交
595

596 597 598 599 600
    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);
        }
601 602
    }

603
    if (phypUUIDTable_WriteFile(conn) == -1)
604 605
        goto err;

606
    if (phypUUIDTable_Push(conn) == -1)
607 608
        goto err;

609
    return 0;
610

611
err:
612
    return -1;
613 614
}

615 616
static int
phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id)
617
{
E
Eduardo Otubo 已提交
618
    phyp_driverPtr phyp_driver = conn->privateData;
619
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
E
Eduardo Otubo 已提交
620

621 622 623 624 625
    uuid_table->nlpars++;
    unsigned int i = uuid_table->nlpars;
    i--;

    if (VIR_REALLOC_N(uuid_table->lpars, uuid_table->nlpars) < 0) {
626
        virReportOOMError();
627
        goto err;
628 629
    }

630 631
    if (VIR_ALLOC(uuid_table->lpars[i]) < 0) {
        virReportOOMError();
632
        goto err;
633
    }
634

635
    uuid_table->lpars[i]->id = id;
636
    memcpy(uuid_table->lpars[i]->uuid, uuid, VIR_UUID_BUFLEN);
637

638 639
    if (phypUUIDTable_WriteFile(conn) == -1)
        goto err;
640

641
    if (phypUUIDTable_Push(conn) == -1)
642 643
        goto err;

644
    return 0;
645

646
err:
647
    return -1;
648 649
}

650 651
static int
phypUUIDTable_ReadFile(virConnectPtr conn)
652
{
E
Eduardo Otubo 已提交
653
    phyp_driverPtr phyp_driver = conn->privateData;
654 655 656 657 658 659
    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;
660

661
    if ((fd = open(local_file, O_RDONLY)) == -1) {
662
        VIR_WARN("Unable to write information to local file.");
663
        goto err;
664 665
    }

666 667 668
    /* 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++) {
669

670 671 672 673 674 675 676 677
            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 {
678
                VIR_WARN
679 680 681
                    ("Unable to read from information to local file.");
                goto err;
            }
682

683 684
            rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN);
            if (rc != VIR_UUID_BUFLEN) {
685
                VIR_WARN("Unable to read information to local file.");
686 687
                goto err;
            }
688
        }
689 690
    } else
        virReportOOMError();
691

692
    VIR_FORCE_CLOSE(fd);
693
    return 0;
694

695
err:
696
    VIR_FORCE_CLOSE(fd);
697
    return -1;
698 699
}

700 701
static int
phypUUIDTable_Pull(virConnectPtr conn)
702 703
{
    ConnectionData *connection_data = conn->networkPrivateData;
704
    LIBSSH2_SESSION *session = connection_data->session;
705 706 707 708 709 710 711 712 713 714 715 716
    LIBSSH2_CHANNEL *channel = NULL;
    virBuffer username = VIR_BUFFER_INITIALIZER;
    struct stat fileinfo;
    char buffer[1024];
    int rc = 0;
    int fd;
    int got = 0;
    int amount = 0;
    int total = 0;
    int sock = 0;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
E
Eduardo Otubo 已提交
717

718
    if (conn->uri->user != NULL) {
719
        virBufferAdd(&username, conn->uri->user, -1);
720

721 722 723 724 725 726
        if (virBufferError(&username)) {
            virBufferFreeAndReset(&username);
            virReportOOMError();
            goto err;
        }
    }
727

728 729 730 731 732 733 734
    if (virAsprintf
        (&remote_file, "/home/%s/libvirt_uuid_table",
         virBufferContentAndReset(&username))
        < 0) {
        virReportOOMError();
        goto err;
    }
735

736 737 738
    /* Trying to stat the remote file. */
    do {
        channel = libssh2_scp_recv(session, remote_file, &fileinfo);
739

740 741 742 743 744 745 746 747 748
        if (!channel) {
            if (libssh2_session_last_errno(session) !=
                LIBSSH2_ERROR_EAGAIN) {
                goto err;;
            } else {
                waitsocket(sock, session);
            }
        }
    } while (!channel);
749

750 751 752
    /* Creating a new data base based on remote file */
    if ((fd = creat(local_file, 0755)) == -1)
        goto err;
753

754 755 756 757
    /* Request a file via SCP */
    while (got < fileinfo.st_size) {
        do {
            amount = sizeof(buffer);
758

759 760 761
            if ((fileinfo.st_size - got) < amount) {
                amount = fileinfo.st_size - got;
            }
E
Eduardo Otubo 已提交
762

763 764 765
            rc = libssh2_channel_read(channel, buffer, amount);
            if (rc > 0) {
                if (safewrite(fd, buffer, rc) != rc)
766
                    VIR_WARN
767
                        ("Unable to write information to local file.");
768

769 770 771 772
                got += rc;
                total += rc;
            }
        } while (rc > 0);
773

774 775 776 777
        if ((rc == LIBSSH2_ERROR_EAGAIN)
            && (got < fileinfo.st_size)) {
            /* this is due to blocking that would occur otherwise
             * so we loop on this condition */
778

779 780 781 782 783
            waitsocket(sock, session);  /* now we wait */
            continue;
        }
        break;
    }
784 785 786 787 788
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
        goto err;
    }
789

790 791 792 793 794 795 796 797 798
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
    virBufferFreeAndReset(&username);
    return 0;
799

800
err:
801 802 803 804 805 806 807
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
808 809 810
    return -1;
}

811 812
static int
phypUUIDTable_Init(virConnectPtr conn)
813
{
E
Eric Blake 已提交
814
    uuid_tablePtr uuid_table = NULL;
815 816 817 818 819
    phyp_driverPtr phyp_driver;
    int nids_numdomains = 0;
    int nids_listdomains = 0;
    int *ids = NULL;
    unsigned int i = 0;
E
Eric Blake 已提交
820 821
    int ret = -1;
    bool table_created = false;
E
Eduardo Otubo 已提交
822

823
    if ((nids_numdomains = phypNumDomainsGeneric(conn, 2)) < 0)
E
Eric Blake 已提交
824
        goto cleanup;
825 826

    if (VIR_ALLOC_N(ids, nids_numdomains) < 0) {
827
        virReportOOMError();
E
Eric Blake 已提交
828
        goto cleanup;
829 830
    }

831 832
    if ((nids_listdomains =
         phypListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0)
E
Eric Blake 已提交
833
        goto cleanup;
834

835
    /* exit early if there are no domains */
E
Eric Blake 已提交
836 837 838 839 840
    if (nids_numdomains == 0 && nids_listdomains == 0) {
        ret = 0;
        goto cleanup;
    }
    if (nids_numdomains != nids_listdomains) {
841
        VIR_ERROR(_("Unable to determine number of domains."));
E
Eric Blake 已提交
842
        goto cleanup;
843
    }
844

845 846 847
    phyp_driver = conn->privateData;
    uuid_table = phyp_driver->uuid_table;
    uuid_table->nlpars = nids_listdomains;
848

849 850 851
    /* try to get the table from server */
    if (phypUUIDTable_Pull(conn) == -1) {
        /* file not found in the server, creating a new one */
E
Eric Blake 已提交
852
        table_created = true;
853 854 855 856
        if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
            for (i = 0; i < uuid_table->nlpars; i++) {
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0) {
                    virReportOOMError();
E
Eric Blake 已提交
857
                    goto cleanup;
858 859
                }
                uuid_table->lpars[i]->id = ids[i];
860

861 862 863 864
                if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0)
                    VIR_WARN("Unable to generate UUID for domain %d",
                             ids[i]);
            }
E
Eduardo Otubo 已提交
865
        } else {
866
            virReportOOMError();
E
Eric Blake 已提交
867
            goto cleanup;
E
Eduardo Otubo 已提交
868
        }
869

870
        if (phypUUIDTable_WriteFile(conn) == -1)
E
Eric Blake 已提交
871
            goto cleanup;
872

873
        if (phypUUIDTable_Push(conn) == -1)
E
Eric Blake 已提交
874
            goto cleanup;
875 876
    } else {
        if (phypUUIDTable_ReadFile(conn) == -1)
E
Eric Blake 已提交
877
            goto cleanup;
878
    }
879

E
Eric Blake 已提交
880
    ret = 0;
881

E
Eric Blake 已提交
882 883 884 885 886 887 888
cleanup:
    if (ret < 0 && table_created) {
        for (i = 0; i < uuid_table->nlpars; i++) {
            VIR_FREE(uuid_table->lpars[i]);
        }
        VIR_FREE(uuid_table->lpars);
    }
889
    VIR_FREE(ids);
E
Eric Blake 已提交
890
    return ret;
891 892
}

893 894
static void
phypUUIDTable_Free(uuid_tablePtr uuid_table)
895
{
896
    int i;
897

898 899 900 901 902 903 904 905
    if (uuid_table == NULL)
        return;

    for (i = 0; i < uuid_table->nlpars; i++)
        VIR_FREE(uuid_table->lpars[i]);

    VIR_FREE(uuid_table->lpars);
    VIR_FREE(uuid_table);
906 907
}

908 909 910 911 912 913 914 915
#define SPECIALCHARACTER_CASES                                                \
    case '&': case ';': case '`': case '@': case '"': case '|': case '*':     \
    case '?': case '~': case '<': case '>': case '^': case '(': case ')':     \
    case '[': case ']': case '{': case '}': case '$': case '%': case '#':     \
    case '\\': case '\n': case '\r': case '\t':

static bool
contains_specialcharacters(const char *src)
916
{
917
    size_t len = strlen(src);
918 919
    size_t i = 0;

920
    if (len == 0)
921
        return false;
922

923 924
    for (i = 0; i < len; i++) {
        switch (src[i]) {
925 926 927 928
        SPECIALCHARACTER_CASES
            return true;
        default:
            continue;
929 930 931
        }
    }

932 933
    return false;
}
934

935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
static char *
escape_specialcharacters(const char *src)
{
    size_t len = strlen(src);
    size_t i = 0, j = 0;
    char *dst;

    if (len == 0)
        return NULL;

    if (VIR_ALLOC_N(dst, len + 1) < 0) {
        virReportOOMError();
        return NULL;
    }

    for (i = 0; i < len; i++) {
        switch (src[i]) {
        SPECIALCHARACTER_CASES
            continue;
        default:
            dst[j] = src[i];
            j++;
        }
    }

    dst[j] = '\0';

    return dst;
963 964
}

965 966 967
static LIBSSH2_SESSION *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
               int *internal_socket)
968
{
969 970 971 972 973 974 975 976 977 978 979
    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;
980
    char *userhome = virGetUserDirectory();
981
    struct stat pvt_stat, pub_stat;
982

983 984
    if (userhome == NULL)
        goto err;
E
Eduardo Otubo 已提交
985

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

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

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

999 1000 1001 1002 1003 1004 1005 1006 1007 1008
        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;
        }
1009

1010
        username = virAuthGetUsername(conn, auth, "ssh", NULL, conn->uri->server);
1011

1012 1013 1014 1015 1016 1017
        if (username == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s",
                       _("Username request failed"));
            goto err;
        }
    }
1018

1019 1020 1021 1022
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
1023

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

1031 1032 1033 1034 1035 1036 1037
    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;
            }
1038
            VIR_FORCE_CLOSE(sock);
1039 1040 1041
        }
        cur = cur->ai_next;
    }
1042

1043 1044 1045 1046
    PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
               _("Failed to connect to %s"), hostname);
    freeaddrinfo(ai);
    goto err;
1047

1048
connected:
1049

1050
    (*internal_socket) = sock;
1051

1052 1053 1054
    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
1055 1056
        goto err;

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

1060 1061 1062 1063 1064 1065 1066
    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;
    }
1067

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

1074 1075 1076 1077 1078 1079
    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
           LIBSSH2_ERROR_EAGAIN) ;
1080

1081
keyboard_interactive:
1082 1083 1084 1085 1086 1087 1088 1089
    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;
        }
1090

1091
        password = virAuthGetPassword(conn, auth, "ssh", username, conn->uri->server);
1092

1093 1094 1095 1096 1097
        if (password == NULL) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s",
                       _("Password request failed"));
            goto disconnect;
        }
1098

1099 1100 1101 1102
        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
               LIBSSH2_ERROR_EAGAIN) ;
1103

1104 1105 1106 1107 1108 1109
        if (rc) {
            PHYP_ERROR(VIR_ERR_AUTH_FAILED,
                       "%s", _("Authentication failed"));
            goto disconnect;
        } else
            goto exit;
1110

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

1114 1115
    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
1116 1117 1118
        goto err;
    }

1119
disconnect:
1120 1121
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1122
err:
1123 1124 1125 1126 1127
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
1128
    return NULL;
1129

1130
exit:
1131 1132 1133 1134 1135 1136
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return session;
1137 1138
}

1139 1140
static virDrvOpenStatus
phypOpen(virConnectPtr conn,
E
Eric Blake 已提交
1141
         virConnectAuthPtr auth, unsigned int flags)
1142 1143 1144 1145 1146 1147 1148 1149
{
    LIBSSH2_SESSION *session = NULL;
    ConnectionData *connection_data = NULL;
    int internal_socket;
    uuid_tablePtr uuid_table = NULL;
    phyp_driverPtr phyp_driver = NULL;
    char *char_ptr;
    char *managed_system = NULL;
E
Eduardo Otubo 已提交
1150

E
Eric Blake 已提交
1151 1152
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    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 (VIR_ALLOC(phyp_driver) < 0) {
1166
        virReportOOMError();
1167
        goto failure;
1168 1169
    }

1170 1171 1172 1173
    if (VIR_ALLOC(uuid_table) < 0) {
        virReportOOMError();
        goto failure;
    }
1174

1175 1176 1177 1178
    if (VIR_ALLOC(connection_data) < 0) {
        virReportOOMError();
        goto failure;
    }
1179

1180 1181 1182 1183 1184 1185
    if (conn->uri->path) {
        /* 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);
E
Eduardo Otubo 已提交
1186

1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
        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';

1200
        if (contains_specialcharacters(conn->uri->path)) {
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
            PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("Error parsing 'path'. Invalid characters."));
            goto failure;
        }
    }

    if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
        PHYP_ERROR(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("Error while opening SSH session."));
        goto failure;
    }

    connection_data->session = session;

    uuid_table->nlpars = 0;
    uuid_table->lpars = NULL;

    if (conn->uri->path)
        phyp_driver->managed_system = managed_system;

    phyp_driver->uuid_table = uuid_table;
    if ((phyp_driver->caps = phypCapsInit()) == NULL) {
1224
        virReportOOMError();
1225
        goto failure;
1226 1227
    }

1228 1229
    conn->privateData = phyp_driver;
    conn->networkPrivateData = connection_data;
1230

1231 1232
    if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
        goto failure;
1233

1234 1235
    if (phypUUIDTable_Init(conn) == -1)
        goto failure;
1236

1237 1238 1239 1240 1241 1242 1243
    if (phyp_driver->system_type == HMC) {
        if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
            goto failure;
    }

    return VIR_DRV_OPEN_SUCCESS;

1244
failure:
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
    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);

    return VIR_DRV_OPEN_ERROR;
1261 1262 1263
}

static int
1264
phypClose(virConnectPtr conn)
1265
{
1266 1267 1268
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
1269

1270 1271
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1272

1273 1274 1275 1276 1277 1278 1279
    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;
}
1280 1281


1282 1283 1284 1285 1286 1287
static int
phypIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Phyp uses an SSH tunnel, so is always encrypted */
    return 1;
}
1288

1289 1290 1291 1292 1293 1294

static int
phypIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Phyp uses an SSH tunnel, so is always secure */
    return 1;
1295 1296
}

1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313

static int
phypIsAlive(virConnectPtr conn)
{
    ConnectionData *connection_data = conn->networkPrivateData;

    /* XXX we should be able to do something better but this is simple, safe,
     * and good enough for now. In worst case, the function will return true
     * even though the connection is not alive.
     */
    if (connection_data && connection_data->session)
        return 1;
    else
        return 0;
}


1314 1315 1316 1317 1318
static int
phypIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
{
    return 0;
}
1319 1320

/* return the lpar_id given a name and a managed system name */
1321
static int
1322 1323
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
1324
{
1325
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1326
    int system_type = phyp_driver->system_type;
1327
    int lpar_id = -1;
E
Eduardo Otubo 已提交
1328 1329
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1330
    virBufferAddLit(&buf, "lssyscfg -r lpar");
E
Eduardo Otubo 已提交
1331
    if (system_type == HMC)
1332 1333
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_names=%s -F lpar_id", name);
E
Eric Blake 已提交
1334
    phypExecInt(session, &buf, conn, &lpar_id);
1335
    return lpar_id;
1336 1337
}

1338 1339 1340 1341
/* 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)
1342 1343
{
    phyp_driverPtr phyp_driver = conn->privateData;
1344 1345 1346 1347
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1348

1349 1350
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
1351 1352
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_ids=%d -F name", lpar_id);
1353
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1354

1355
    if (exit_status < 0)
1356 1357
        VIR_FREE(ret);
    return ret;
1358 1359
}

1360 1361 1362 1363 1364 1365 1366 1367 1368

/* 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
 * */
static int
phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn)
1369 1370
{
    phyp_driverPtr phyp_driver = conn->privateData;
1371 1372 1373
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
    unsigned int i = 0;
1374

1375 1376
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
1377
            memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
1378 1379 1380
            return 0;
        }
    }
1381

1382
    return -1;
1383 1384
}

1385 1386 1387 1388 1389 1390 1391 1392
/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
static unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
1393
{
1394 1395 1396 1397 1398 1399
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    phyp_driverPtr phyp_driver = conn->privateData;
    int system_type = phyp_driver->system_type;
    int memory = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1400

1401 1402
    if (type != 1 && type != 0)
        return 0;
1403

1404 1405
    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1406 1407
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1408 1409
                      " -r mem --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_mem" : "curr_max_mem", lpar_id);
E
Eric Blake 已提交
1410
    phypExecInt(session, &buf, conn, &memory);
1411
    return memory;
1412 1413
}

1414 1415 1416
static unsigned long
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
1417
{
1418
    ConnectionData *connection_data = conn->networkPrivateData;
1419
    LIBSSH2_SESSION *session = connection_data->session;
1420
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1421
    int system_type = phyp_driver->system_type;
1422
    int vcpus = 0;
E
Eduardo Otubo 已提交
1423
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1424

1425
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1426
    if (system_type == HMC)
1427 1428
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1429 1430
                      " -r proc --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_max_procs" : "curr_procs", lpar_id);
E
Eric Blake 已提交
1431
    phypExecInt(session, &buf, conn, &vcpus);
1432
    return vcpus;
1433
}
1434

1435 1436 1437 1438
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
    return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
1439 1440
}

1441
static int
1442
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
1443 1444 1445
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;
1446

1447 1448 1449 1450 1451
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
        PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

1452 1453 1454
    return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}

1455 1456 1457 1458 1459 1460 1461
static int
phypGetLparCPUMAX(virDomainPtr dom)
{
    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1462 1463 1464
static int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
1465
{
1466 1467
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1468
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1469
    int system_type = phyp_driver->system_type;
1470
    int remote_slot = -1;
E
Eduardo Otubo 已提交
1471 1472
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1473
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1474
    if (system_type == HMC)
1475 1476
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1477
                      "remote_slot_num --filter lpar_names=%s", lpar_name);
E
Eric Blake 已提交
1478
    phypExecInt(session, &buf, conn, &remote_slot);
1479
    return remote_slot;
1480 1481
}

1482 1483 1484 1485 1486 1487
/* XXX - is this needed? */
static char *phypGetBackingDevice(virConnectPtr, const char *, char *)
    ATTRIBUTE_UNUSED;
static char *
phypGetBackingDevice(virConnectPtr conn, const char *managed_system,
                     char *lpar_name)
1488
{
1489 1490
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1491
    phyp_driverPtr phyp_driver = conn->privateData;
1492 1493 1494 1495 1496 1497 1498
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int remote_slot = 0;
    int exit_status = 0;
    char *char_ptr;
    char *backing_device = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1499

1500 1501 1502 1503 1504 1505
    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        return NULL;

    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1506 1507
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1508
                      "backing_devices --filter slots=%d", remote_slot);
1509
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1510

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

1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
    /* 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
1528
            goto cleanup;
1529 1530 1531 1532 1533

        backing_device = strdup(char_ptr);

        if (backing_device == NULL) {
            virReportOOMError();
1534
            goto cleanup;
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
        }
    } else {
        backing_device = ret;
        ret = NULL;
    }

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

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

1546
cleanup:
1547
    VIR_FREE(ret);
1548

1549
    return backing_device;
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
}

static char *
phypGetLparProfile(virConnectPtr conn, int lpar_id)
{
    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 system_type = phyp_driver->system_type;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1566 1567
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1568 1569
                      " -r prof --filter lpar_ids=%d -F name|head -n 1",
                      lpar_id);
1570
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1571

1572
    if (exit_status < 0)
1573 1574
        VIR_FREE(ret);
    return ret;
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
}

static int
phypGetVIOSNextSlotNumber(virConnectPtr conn)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    char *profile = NULL;
1587
    int slot = -1;
1588 1589 1590
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1591
        VIR_ERROR(_("Unable to get VIOS profile name."));
1592
        return -1;
1593 1594 1595 1596 1597
    }

    virBufferAddLit(&buf, "lssyscfg");

    if (system_type == HMC)
1598
        virBufferAsprintf(&buf, " -m %s", managed_system);
1599

1600
    virBufferAsprintf(&buf, " -r prof --filter "
1601 1602 1603 1604 1605
                      "profile_names=%s -F virtual_eth_adapters,"
                      "virtual_opti_pool_id,virtual_scsi_adapters,"
                      "virtual_serial_adapters|sed -e 's/\"//g' -e "
                      "'s/,/\\n/g'|sed -e 's/\\(^[0-9][0-9]\\*\\).*$/\\1/'"
                      "|sort|tail -n 1", profile);
E
Eric Blake 已提交
1606 1607 1608
    if (phypExecInt(session, &buf, conn, &slot) < 0)
        return -1;
    return slot + 1;
1609 1610 1611 1612 1613
}

static int
phypCreateServerSCSIAdapter(virConnectPtr conn)
{
1614
    int result = -1;
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    char *profile = NULL;
    int slot = 0;
    char *vios_name = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1631
        VIR_ERROR(_("Unable to get VIOS name"));
1632
        goto cleanup;
1633 1634 1635
    }

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1636
        VIR_ERROR(_("Unable to get VIOS profile name."));
1637
        goto cleanup;
1638 1639 1640
    }

    if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
1641
        VIR_ERROR(_("Unable to get free slot number"));
1642
        goto cleanup;
1643 1644 1645 1646 1647 1648 1649
    }

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1650 1651
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof --filter lpar_ids=%d,profile_names=%s"
1652 1653
                      " -F virtual_scsi_adapters|sed -e s/\\\"//g",
                      vios_id, profile);
1654
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1655 1656

    if (exit_status < 0 || ret == NULL)
1657
        goto cleanup;
1658 1659 1660 1661 1662 1663

    /* Here I change the VIOS configuration to append the new adapter
     * with the free slot I got with phypGetVIOSNextSlotNumber.
     * */
    virBufferAddLit(&buf, "chsyscfg");
    if (system_type == HMC)
1664 1665
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d,"
1666 1667
                      "\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'",
                      vios_name, vios_id, ret, slot);
1668
    VIR_FREE(ret);
1669
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1670 1671

    if (exit_status < 0 || ret == NULL)
1672
        goto cleanup;
1673 1674 1675 1676 1677 1678

    /* Finally I add the new scsi adapter to VIOS using the same slot
     * I used in the VIOS configuration.
     * */
    virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi");
    if (system_type == HMC)
1679 1680
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1681 1682
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      vios_name, slot);
1683
    VIR_FREE(ret);
1684
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1685 1686

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

1689
    result = 0;
1690

1691
cleanup:
1692 1693 1694
    VIR_FREE(profile);
    VIR_FREE(vios_name);
    VIR_FREE(ret);
1695 1696

    return result;
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
}

static char *
phypGetVIOSFreeSCSIAdapter(virConnectPtr conn)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1713
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1714 1715
                          managed_system, vios_id);

1716
    virBufferAsprintf(&buf, "lsmap -all -field svsa backing -fmt , ");
1717 1718 1719 1720

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

1721
    virBufferAsprintf(&buf, "|sed '/,[^.*]/d; s/,//g; q'");
1722
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1723

1724
    if (exit_status < 0)
1725 1726
        VIR_FREE(ret);
    return ret;
1727 1728 1729 1730 1731 1732
}


static int
phypAttachDevice(virDomainPtr domain, const char *xml)
{
1733
    int result = -1;
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
    virConnectPtr conn = domain->conn;
    ConnectionData *connection_data = domain->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = domain->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    char *scsi_adapter = NULL;
    int slot = 0;
    char *vios_name = NULL;
    char *profile = NULL;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *domain_name = NULL;

E
Eric Blake 已提交
1752 1753 1754 1755 1756
    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        goto cleanup;
    }

1757
    domain_name = escape_specialcharacters(domain->name);
1758

1759
    if (domain_name == NULL) {
1760
        goto cleanup;
1761 1762 1763 1764 1765 1766
    }

    def->os.type = strdup("aix");

    if (def->os.type == NULL) {
        virReportOOMError();
1767
        goto cleanup;
1768 1769 1770 1771 1772
    }

    dev = virDomainDeviceDefParse(phyp_driver->caps, def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (!dev) {
1773
        goto cleanup;
1774 1775 1776 1777 1778
    }

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1779
        VIR_ERROR(_("Unable to get VIOS name"));
1780
        goto cleanup;
1781 1782 1783 1784 1785 1786 1787 1788
    }

    /* First, let's look for a free SCSI Adapter
     * */
    if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
        /* If not found, let's create one.
         * */
        if (phypCreateServerSCSIAdapter(conn) == -1) {
1789
            VIR_ERROR(_("Unable to create new virtual adapter"));
1790
            goto cleanup;
1791 1792
        } else {
            if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
1793
                VIR_ERROR(_("Unable to create new virtual adapter"));
1794
                goto cleanup;
1795 1796 1797 1798 1799
            }
        }
    }

    if (system_type == HMC)
1800
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1801 1802
                          managed_system, vios_id);

1803
    virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
1804 1805 1806 1807
                      dev->data.disk->src, scsi_adapter);

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1808
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1809 1810

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

    if (!(profile = phypGetLparProfile(conn, domain->id))) {
1814
        VIR_ERROR(_("Unable to get VIOS profile name."));
1815
        goto cleanup;
1816 1817 1818 1819 1820 1821
    }

    /* Let's get the slot number for the adapter we just created
     * */
    virBufferAddLit(&buf, "lshwres -r virtualio --rsubtype scsi");
    if (system_type == HMC)
1822 1823
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1824 1825
                      " slot_num,backing_device|grep %s|cut -d, -f1",
                      dev->data.disk->src);
E
Eric Blake 已提交
1826
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1827
        goto cleanup;
1828 1829 1830 1831 1832 1833

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1834 1835
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1836 1837 1838
                      " -r prof --filter lpar_ids=%d,profile_names=%s"
                      " -F virtual_scsi_adapters|sed -e 's/\"//g'",
                      vios_id, profile);
1839
    VIR_FREE(ret);
1840
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1841 1842

    if (exit_status < 0 || ret == NULL)
1843
        goto cleanup;
1844 1845 1846 1847 1848 1849

    /* Here I change the LPAR configuration to append the new adapter
     * with the new slot we just created
     * */
    virBufferAddLit(&buf, "chsyscfg");
    if (system_type == HMC)
1850 1851
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1852 1853 1854 1855
                      " -r prof -i 'name=%s,lpar_id=%d,"
                      "\"virtual_scsi_adapters=%s,%d/client/%d/%s/0\"'",
                      domain_name, domain->id, ret, slot,
                      vios_id, vios_name);
E
Eric Blake 已提交
1856
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1857
        goto cleanup;
1858 1859 1860 1861 1862 1863

    /* Finally I add the new scsi adapter to VIOS using the same slot
     * I used in the VIOS configuration.
     * */
    virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi");
    if (system_type == HMC)
1864 1865
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1866 1867
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      domain_name, slot);
1868
    VIR_FREE(ret);
1869
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1870 1871

    if (exit_status < 0 || ret == NULL) {
1872
        VIR_ERROR(_
1873 1874
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    "Contact your support to enable this feature."));
1875
        goto cleanup;
1876 1877
    }

1878
    result = 0;
1879

1880
cleanup:
1881
    VIR_FREE(ret);
1882 1883
    virDomainDeviceDefFree(dev);
    virDomainDefFree(def);
1884 1885
    VIR_FREE(vios_name);
    VIR_FREE(scsi_adapter);
1886 1887 1888 1889
    VIR_FREE(profile);
    VIR_FREE(domain_name);

    return result;
1890 1891
}

1892 1893
static char *
phypVolumeGetKey(virConnectPtr conn, const char *name)
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1906
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1907 1908
                          managed_system, vios_id);

1909
    virBufferAsprintf(&buf, "lslv %s -field lvid", name);
1910 1911 1912 1913

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

1914
    virBufferAsprintf(&buf, "|sed -e 's/^LV IDENTIFIER://' -e 's/ //g'");
1915
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1916

1917
    if (exit_status < 0)
1918 1919
        VIR_FREE(ret);
    return ret;
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
}

static char *
phypGetStoragePoolDevice(virConnectPtr conn, char *name)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1936
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1937 1938
                          managed_system, vios_id);

1939
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
1940 1941 1942 1943

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

1944
    virBufferAsprintf(&buf, "|sed '1d; s/ //g'");
1945
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1946

1947
    if (exit_status < 0)
1948 1949
        VIR_FREE(ret);
    return ret;
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
}

static unsigned long int
phypGetStoragePoolSize(virConnectPtr conn, char *name)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
1961
    int sp_size = -1;
1962 1963 1964
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1965
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1966 1967
                          managed_system, vios_id);

1968
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
1969 1970 1971 1972

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

1973
    virBufferAsprintf(&buf, "|sed '1d; s/ //g'");
E
Eric Blake 已提交
1974
    phypExecInt(session, &buf, conn, &sp_size);
1975
    return sp_size;
1976 1977
}

1978
static char *
1979
phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname,
1980
                unsigned int capacity)
1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int vios_id = phyp_driver->vios_id;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1991
    char *key = NULL;
1992 1993

    if (system_type == HMC)
1994
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1995 1996
                          managed_system, vios_id);

1997
    virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
1998 1999 2000

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2001
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2002 2003

    if (exit_status < 0) {
2004
        VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
2005
        goto cleanup;
2006 2007
    }

2008 2009
    key = phypVolumeGetKey(conn, lvname);

2010
cleanup:
2011 2012
    VIR_FREE(ret);

2013
    return key;
2014 2015 2016 2017 2018
}

static virStorageVolPtr
phypVolumeLookupByName(virStoragePoolPtr pool, const char *volname)
{
2019 2020
    char *key;
    virStorageVolPtr vol;
2021

2022
    key = phypVolumeGetKey(pool->conn, volname);
2023

2024
    if (key == NULL)
2025 2026
        return NULL;

2027 2028 2029 2030 2031
    vol = virGetStorageVol(pool->conn, pool->name, volname, key);

    VIR_FREE(key);

    return vol;
2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
}

static virStorageVolPtr
phypStorageVolCreateXML(virStoragePoolPtr pool,
                        const char *xml, unsigned int flags)
{
    virCheckFlags(0, NULL);

    virStorageVolDefPtr voldef = NULL;
    virStoragePoolDefPtr spdef = NULL;
    virStorageVolPtr vol = NULL;
2043
    virStorageVolPtr dup_vol = NULL;
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
    char *key = NULL;

    if (VIR_ALLOC(spdef) < 0) {
        virReportOOMError();
        return NULL;
    }

    /* Filling spdef manually
     * */
    if (pool->name != NULL) {
        spdef->name = pool->name;
    } else {
2056
        VIR_ERROR(_("Unable to determine storage pool's name."));
2057 2058 2059 2060
        goto err;
    }

    if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2061
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2062 2063 2064 2065 2066
        goto err;
    }

    if ((spdef->capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2067
        VIR_ERROR(_("Unable to determine storage pools's size."));
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
        goto err;
    }

    /* Information not avaliable */
    spdef->allocation = 0;
    spdef->available = 0;

    spdef->source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
    if ((spdef->source.adapter =
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2080
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2081 2082 2083 2084
        goto err;
    }

    if ((voldef = virStorageVolDefParseString(spdef, xml)) == NULL) {
2085
        VIR_ERROR(_("Error parsing volume XML."));
2086 2087 2088 2089
        goto err;
    }

    /* checking if this name already exists on this system */
2090
    if ((dup_vol = phypVolumeLookupByName(pool, voldef->name)) != NULL) {
2091
        VIR_ERROR(_("StoragePool name already exists."));
2092
        virUnrefStorageVol(dup_vol);
2093 2094 2095 2096 2097 2098 2099
        goto err;
    }

    /* The key must be NULL, the Power Hypervisor creates a key
     * in the moment you create the volume.
     * */
    if (voldef->key) {
2100
        VIR_ERROR(_("Key must be empty, Power Hypervisor will create one for you."));
2101 2102 2103 2104
        goto err;
    }

    if (voldef->capacity) {
2105
        VIR_ERROR(_("Capacity cannot be empty."));
2106 2107 2108
        goto err;
    }

2109 2110 2111 2112
    key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
                          voldef->capacity);

    if (key == NULL)
2113 2114 2115 2116 2117 2118 2119
        goto err;

    if ((vol =
         virGetStorageVol(pool->conn, pool->name, voldef->name,
                          key)) == NULL)
        goto err;

2120 2121
    VIR_FREE(key);

2122 2123
    return vol;

2124
err:
2125
    VIR_FREE(key);
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
    virStorageVolDefFree(voldef);
    virStoragePoolDefFree(spdef);
    if (vol)
        virUnrefStorageVol(vol);
    return NULL;
}

static char *
phypVolumeGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp)
{
    virConnectPtr conn = vol->conn;
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2148
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2149 2150
                          managed_system, vios_id);

2151
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
2152 2153 2154 2155

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2156
    virBufferAsprintf(&buf, "|sed 1d");
2157
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2158

2159
    if (exit_status < 0)
2160 2161
        VIR_FREE(ret);
    return ret;
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
}

static virStorageVolPtr
phypVolumeLookupByPath(virConnectPtr conn, const char *volname)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
2174
    char *ret = NULL;
2175 2176
    char *key = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2177
    virStorageVolPtr vol = NULL;
2178 2179

    if (system_type == HMC)
2180
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2181 2182
                          managed_system, vios_id);

2183
    virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
2184 2185 2186 2187

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2188
    virBufferAsprintf(&buf, "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2189
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2190

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

2194
    key = phypVolumeGetKey(conn, volname);
2195

2196
    if (key == NULL)
2197
        goto cleanup;
2198

2199
    vol = virGetStorageVol(conn, ret, volname, key);
2200

2201
cleanup:
2202
    VIR_FREE(ret);
2203 2204 2205
    VIR_FREE(key);

    return vol;
2206 2207 2208 2209 2210 2211
}

static int
phypGetStoragePoolUUID(virConnectPtr conn, unsigned char *uuid,
                       const char *name)
{
2212
    int result = -1;
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2224
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2225 2226
                          managed_system, vios_id);

2227
    virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
2228 2229 2230 2231

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2232
    virBufferAsprintf(&buf, "|sed '1,2d'");
2233
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2234 2235

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

2238
    if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
2239
        goto cleanup;
2240

2241
    result = 0;
2242

2243
cleanup:
2244
    VIR_FREE(ret);
2245 2246

    return result;
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
}

static virStoragePoolPtr
phypStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
    unsigned char uuid[VIR_UUID_BUFLEN];

    if (phypGetStoragePoolUUID(conn, uuid, name) == -1)
        return NULL;

    return virGetStoragePool(conn, name, uuid);
}

static char *
phypVolumeGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
2263 2264 2265
    virStorageVolDef voldef;
    virStoragePoolDef pool;
    virStoragePoolPtr sp;
2266
    char *xml = NULL;
2267

2268 2269 2270
    virCheckFlags(0, NULL);

    memset(&voldef, 0, sizeof(virStorageVolDef));
2271
    memset(&pool, 0, sizeof(virStoragePoolDef));
2272

2273
    sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
2274 2275

    if (!sp)
2276
        goto cleanup;
2277 2278 2279 2280

    if (sp->name != NULL) {
        pool.name = sp->name;
    } else {
2281
        VIR_ERROR(_("Unable to determine storage sp's name."));
2282
        goto cleanup;
2283 2284
    }

2285
    if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
2286
        VIR_ERROR(_("Unable to determine storage sp's uuid."));
2287
        goto cleanup;
2288 2289 2290
    }

    if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
2291
        VIR_ERROR(_("Unable to determine storage sps's size."));
2292
        goto cleanup;
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
    }

    /* Information not avaliable */
    pool.allocation = 0;
    pool.available = 0;

    pool.source.ndevice = 1;

    if ((pool.source.adapter =
         phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) {
2303
        VIR_ERROR(_("Unable to determine storage sps's source adapter."));
2304
        goto cleanup;
2305 2306 2307 2308 2309
    }

    if (vol->name != NULL)
        voldef.name = vol->name;
    else {
2310
        VIR_ERROR(_("Unable to determine storage pool's name."));
2311
        goto cleanup;
2312 2313
    }

2314 2315 2316 2317
    voldef.key = strdup(vol->key);

    if (voldef.key == NULL) {
        virReportOOMError();
2318
        goto cleanup;
2319 2320 2321 2322
    }

    voldef.type = VIR_STORAGE_POOL_LOGICAL;

2323 2324 2325 2326
    xml = virStorageVolDefFormat(&pool, &voldef);

    VIR_FREE(voldef.key);

2327 2328 2329
cleanup:
    if (sp)
        virUnrefStoragePool(sp);
2330
    return xml;
2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
}

/* The Volume Group path here will be treated as suggested in the
 * email on the libvirt mailling list. As soon as I can't get the
 * path for every volume, the path will be a representation in
 * the form:
 *
 * /physical_volume/storage_pool/logical_volume
 *
 * */
static char *
phypVolumeGetPath(virStorageVolPtr vol)
{
    virConnectPtr conn = vol->conn;
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
2352
    char *ret = NULL;
2353 2354
    char *path = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2355
    char *pv;
2356 2357

    if (system_type == HMC)
2358
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2359 2360
                          managed_system, vios_id);

2361
    virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
2362 2363 2364 2365

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2366
    virBufferAsprintf(&buf,
2367
                      "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2368
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2369

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

2373
    pv = phypVolumeGetPhysicalVolumeByStoragePool(vol, ret);
2374

2375 2376
    if (!pv)
        goto cleanup;
2377

2378
    if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0) {
2379 2380 2381
        virReportOOMError();
        goto cleanup;
    }
2382

2383
cleanup:
2384
    VIR_FREE(ret);
2385
    VIR_FREE(path);
2386 2387

    return path;
2388 2389 2390 2391 2392 2393
}

static int
phypStoragePoolListVolumes(virStoragePoolPtr pool, char **const volumes,
                           int nvolumes)
{
2394
    bool success = false;
2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406
    virConnectPtr conn = pool->conn;
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    int got = 0;
    int i;
    char *ret = NULL;
    char *volumes_list = NULL;
E
Eric Blake 已提交
2407
    char *char_ptr = NULL;
2408 2409 2410
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2411
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2412 2413
                          managed_system, vios_id);

2414
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2415 2416 2417 2418

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2419
    virBufferAsprintf(&buf, "|sed '1,2d'");
2420
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2421 2422 2423

    /* I need to parse the textual return in order to get the volumes */
    if (exit_status < 0 || ret == NULL)
2424
        goto cleanup;
2425 2426 2427 2428
    else {
        volumes_list = ret;

        while (got < nvolumes) {
E
Eric Blake 已提交
2429
            char_ptr = strchr(volumes_list, '\n');
2430

E
Eric Blake 已提交
2431 2432
            if (char_ptr) {
                *char_ptr = '\0';
2433 2434
                if ((volumes[got++] = strdup(volumes_list)) == NULL) {
                    virReportOOMError();
2435
                    goto cleanup;
2436
                }
E
Eric Blake 已提交
2437 2438
                char_ptr++;
                volumes_list = char_ptr;
2439 2440 2441 2442 2443
            } else
                break;
        }
    }

2444 2445
    success = true;

2446
cleanup:
2447 2448 2449 2450 2451 2452
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(volumes[i]);

        got = -1;
    }
2453
    VIR_FREE(ret);
2454
    return got;
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
}

static int
phypStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
    virConnectPtr conn = pool->conn;
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
2465
    int nvolumes = -1;
2466 2467 2468 2469 2470
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2471
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2472
                          managed_system, vios_id);
2473
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2474 2475
    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2476
    virBufferAsprintf(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2477 2478
    if (phypExecInt(session, &buf, conn, &nvolumes) < 0)
        return -1;
2479 2480

    /* We need to remove 2 line from the header text output */
E
Eric Blake 已提交
2481
    return nvolumes - 2;
2482 2483 2484 2485 2486
}

static int
phypDestroyStoragePool(virStoragePoolPtr pool)
{
2487
    int result = -1;
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499
    virConnectPtr conn = pool->conn;
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int vios_id = phyp_driver->vios_id;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2500
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2501 2502
                          managed_system, vios_id);

2503
    virBufferAsprintf(&buf, "rmsp %s", pool->name);
2504 2505 2506

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2507
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2508 2509

    if (exit_status < 0) {
2510
        VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
2511
        goto cleanup;
2512 2513
    }

2514
    result = 0;
2515

2516
cleanup:
2517
    VIR_FREE(ret);
2518 2519

    return result;
2520 2521 2522 2523 2524
}

static int
phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
{
2525
    int result = -1;
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virStoragePoolSource source = def->source;
    int vios_id = phyp_driver->vios_id;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2538
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2539 2540
                          managed_system, vios_id);

2541
    virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
2542 2543 2544 2545
                      source.adapter);

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2546
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2547 2548

    if (exit_status < 0) {
2549
        VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
2550
        goto cleanup;
2551 2552
    }

2553
    result = 0;
2554

2555
cleanup:
2556
    VIR_FREE(ret);
2557 2558

    return result;
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568

}

static int
phypNumOfStoragePools(virConnectPtr conn)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
2569
    int nsp = -1;
2570 2571 2572 2573 2574
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2575
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2576 2577
                          managed_system, vios_id);

2578
    virBufferAsprintf(&buf, "lsvg");
2579 2580 2581 2582

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');

2583
    virBufferAsprintf(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2584
    phypExecInt(session, &buf, conn, &nsp);
2585
    return nsp;
2586 2587 2588 2589 2590
}

static int
phypListStoragePools(virConnectPtr conn, char **const pools, int npools)
{
2591
    bool success = false;
2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    int got = 0;
    int i;
    char *ret = NULL;
    char *storage_pools = NULL;
E
Eric Blake 已提交
2603
    char *char_ptr = NULL;
2604 2605 2606
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2607
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2608 2609
                          managed_system, vios_id);

2610
    virBufferAsprintf(&buf, "lsvg");
2611 2612 2613

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2614
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2615 2616 2617

    /* I need to parse the textual return in order to get the storage pools */
    if (exit_status < 0 || ret == NULL)
2618
        goto cleanup;
2619 2620 2621 2622
    else {
        storage_pools = ret;

        while (got < npools) {
E
Eric Blake 已提交
2623
            char_ptr = strchr(storage_pools, '\n');
2624

E
Eric Blake 已提交
2625 2626
            if (char_ptr) {
                *char_ptr = '\0';
2627 2628
                if ((pools[got++] = strdup(storage_pools)) == NULL) {
                    virReportOOMError();
2629
                    goto cleanup;
2630
                }
E
Eric Blake 已提交
2631 2632
                char_ptr++;
                storage_pools = char_ptr;
2633 2634 2635 2636 2637
            } else
                break;
        }
    }

2638 2639
    success = true;

2640
cleanup:
2641 2642 2643 2644 2645 2646
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(pools[i]);

        got = -1;
    }
2647
    VIR_FREE(ret);
2648
    return got;
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
}

static virStoragePoolPtr
phypGetStoragePoolLookUpByUUID(virConnectPtr conn,
                               const unsigned char *uuid)
{
    virStoragePoolPtr sp = NULL;
    int npools = 0;
    int gotpools = 0;
    char **pools = NULL;
    unsigned int i = 0;
    unsigned char *local_uuid = NULL;

    if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0) {
        virReportOOMError();
        goto err;
    }

    if ((npools = phypNumOfStoragePools(conn)) == -1) {
        virReportOOMError();
        goto err;
    }

    if (VIR_ALLOC_N(pools, npools) < 0) {
        virReportOOMError();
        goto err;
    }

    if ((gotpools = phypListStoragePools(conn, pools, npools)) == -1) {
        virReportOOMError();
        goto err;
    }

    if (gotpools != npools) {
        virReportOOMError();
        goto err;
    }

    for (i = 0; i < gotpools; i++) {
        if (phypGetStoragePoolUUID(conn, local_uuid, pools[i]) == -1)
            continue;

        if (!memcmp(local_uuid, uuid, VIR_UUID_BUFLEN)) {
            sp = virGetStoragePool(conn, pools[i], uuid);
            VIR_FREE(local_uuid);
            VIR_FREE(pools);

            if (sp)
                return sp;
            else
                goto err;
        }
    }

2703
err:
2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715
    VIR_FREE(local_uuid);
    VIR_FREE(pools);
    return NULL;
}

static virStoragePoolPtr
phypStoragePoolCreateXML(virConnectPtr conn,
                         const char *xml, unsigned int flags)
{
    virCheckFlags(0, NULL);

    virStoragePoolDefPtr def = NULL;
2716
    virStoragePoolPtr dup_sp = NULL;
2717 2718 2719 2720 2721 2722
    virStoragePoolPtr sp = NULL;

    if (!(def = virStoragePoolDefParseString(xml)))
        goto err;

    /* checking if this name already exists on this system */
2723
    if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) {
2724
        VIR_WARN("StoragePool name already exists.");
2725
        virUnrefStoragePool(dup_sp);
2726 2727 2728 2729
        goto err;
    }

    /* checking if ID or UUID already exists on this system */
2730
    if ((dup_sp = phypGetStoragePoolLookUpByUUID(conn, def->uuid)) != NULL) {
2731
        VIR_WARN("StoragePool uuid already exists.");
2732
        virUnrefStoragePool(dup_sp);
2733 2734
        goto err;
    }
2735

2736 2737 2738 2739 2740 2741 2742 2743
    if ((sp = virGetStoragePool(conn, def->name, def->uuid)) == NULL)
        goto err;

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

    return sp;

2744
err:
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
    virStoragePoolDefFree(def);
    if (sp)
        virUnrefStoragePool(sp);
    return NULL;
}

static char *
phypGetStoragePoolXMLDesc(virStoragePoolPtr pool, unsigned int flags)
{
    virCheckFlags(0, NULL);

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

    if (pool->name != NULL)
        def.name = pool->name;
    else {
2762
        VIR_ERROR(_("Unable to determine storage pool's name."));
2763 2764 2765
        goto err;
    }

2766
    if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2767
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2768 2769 2770 2771 2772
        goto err;
    }

    if ((def.capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2773
        VIR_ERROR(_("Unable to determine storage pools's size."));
2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
        goto err;
    }

    /* Information not avaliable */
    def.allocation = 0;
    def.available = 0;

    def.source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
    if ((def.source.adapter =
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2786
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2787 2788 2789 2790 2791
        goto err;
    }

    return virStoragePoolDefFormat(&def);

2792
err:
2793
    return NULL;
2794 2795
}

E
Eduardo Otubo 已提交
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
static int
phypInterfaceDestroy(virInterfacePtr iface,
                     unsigned int flags)
{
    virCheckFlags(0, -1);

    ConnectionData *connection_data = iface->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = iface->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int exit_status = 0;
    int slot_num = 0;
    int lpar_id = 0;
    char *ret = NULL;
E
Eric Blake 已提交
2812
    int rv = -1;
E
Eduardo Otubo 已提交
2813 2814 2815 2816 2817

    /* Getting the remote slot number */

    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2818
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2819

2820
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2821 2822 2823
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,slot_num|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2824
    if (phypExecInt(session, &buf, iface->conn, &slot_num) < 0)
E
Eric Blake 已提交
2825
        goto cleanup;
E
Eduardo Otubo 已提交
2826 2827 2828 2829

    /* Getting the remote slot number */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2830
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2831

2832
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2833 2834 2835
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,lpar_id|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2836
    if (phypExecInt(session, &buf, iface->conn, &lpar_id) < 0)
E
Eric Blake 已提交
2837
        goto cleanup;
E
Eduardo Otubo 已提交
2838 2839 2840 2841

    /* excluding interface */
    virBufferAddLit(&buf, "chhwres ");
    if (system_type == HMC)
2842
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2843

2844
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2845 2846
                      " -r virtualio --rsubtype eth"
                      " --id %d -o r -s %d", lpar_id, slot_num);
2847 2848
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, iface->conn, false);
E
Eduardo Otubo 已提交
2849 2850

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2851
        goto cleanup;
E
Eduardo Otubo 已提交
2852

E
Eric Blake 已提交
2853
    rv = 0;
E
Eduardo Otubo 已提交
2854

E
Eric Blake 已提交
2855
cleanup:
E
Eduardo Otubo 已提交
2856
    VIR_FREE(ret);
E
Eric Blake 已提交
2857
    return rv;
E
Eduardo Otubo 已提交
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877
}

static virInterfacePtr
phypInterfaceDefineXML(virConnectPtr conn, const char *xml,
                       unsigned int flags)
{
    virCheckFlags(0, NULL);

    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int exit_status = 0;
    int slot = 0;
    char *ret = NULL;
    char name[PHYP_IFACENAME_SIZE];
    char mac[PHYP_MAC_SIZE];
    virInterfaceDefPtr def;
E
Eric Blake 已提交
2878
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2879 2880

    if (!(def = virInterfaceDefParseString(xml)))
E
Eric Blake 已提交
2881
        goto cleanup;
E
Eduardo Otubo 已提交
2882 2883 2884 2885

    /* Now need to get the next free slot number */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2886
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2887

2888
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2889 2890 2891
                      " -r virtualio --rsubtype slot --level slot"
                      " -Fslot_num --filter lpar_names=%s"
                      " |sort|tail -n 1", def->name);
E
Eric Blake 已提交
2892
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2893
        goto cleanup;
E
Eduardo Otubo 已提交
2894 2895 2896 2897 2898 2899 2900

    /* The next free slot itself: */
    slot++;

    /* Now adding the new network interface */
    virBufferAddLit(&buf, "chhwres ");
    if (system_type == HMC)
2901
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2902

2903
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2904 2905 2906
                      " -r virtualio --rsubtype eth"
                      " -p %s -o a -s %d -a port_vlan_id=1,"
                      "ieee_virtual_eth=0", def->name, slot);
2907 2908
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2909 2910

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2911
        goto cleanup;
E
Eduardo Otubo 已提交
2912 2913 2914 2915 2916 2917 2918 2919 2920

    /* Need to sleep a little while to wait for the HMC to
     * complete the execution of the command.
     * */
    sleep(1);

    /* Getting the new interface name */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2921
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2922

2923
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2924 2925 2926
                      " -r virtualio --rsubtype slot --level slot"
                      " |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
                      "s/^.*drc_name=//'", def->name, slot);
2927 2928
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2929 2930 2931 2932 2933

    if (exit_status < 0 || ret == NULL) {
        /* roll back and excluding interface if error*/
        virBufferAddLit(&buf, "chhwres ");
        if (system_type == HMC)
2934
            virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2935

2936
        virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2937 2938
                " -r virtualio --rsubtype eth"
                " -p %s -o r -s %d", def->name, slot);
2939 2940
        VIR_FREE(ret);
        ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eric Blake 已提交
2941
        goto cleanup;
E
Eduardo Otubo 已提交
2942 2943 2944 2945 2946 2947 2948
    }

    memcpy(name, ret, PHYP_IFACENAME_SIZE-1);

    /* Getting the new interface mac addr */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2949
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2950

2951
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2952 2953 2954
                      "-r virtualio --rsubtype eth --level lpar "
                      " |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
                      "s/^.*mac_addr=//'", def->name, slot);
2955 2956
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2957 2958

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2959
        goto cleanup;
E
Eduardo Otubo 已提交
2960 2961 2962

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

E
Eric Blake 已提交
2963
    result = virGetInterface(conn, name, mac);
E
Eduardo Otubo 已提交
2964

E
Eric Blake 已提交
2965
cleanup:
E
Eduardo Otubo 已提交
2966 2967
    VIR_FREE(ret);
    virInterfaceDefFree(def);
E
Eric Blake 已提交
2968
    return result;
E
Eduardo Otubo 已提交
2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984
}

static virInterfacePtr
phypInterfaceLookupByName(virConnectPtr conn, const char *name)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int exit_status = 0;
    char *ret = NULL;
    int slot = 0;
    int lpar_id = 0;
    char mac[PHYP_MAC_SIZE];
2985
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2986 2987 2988 2989

    /*Getting the slot number for the interface */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
2990
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2991

2992
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2993 2994 2995
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,slot_num |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
2996
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2997
        goto cleanup;
E
Eduardo Otubo 已提交
2998 2999 3000 3001

    /*Getting the lpar_id for the interface */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
3002
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
3003

3004
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3005 3006 3007
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,lpar_id |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
3008
    if (phypExecInt(session, &buf, conn, &lpar_id) < 0)
E
Eric Blake 已提交
3009
        goto cleanup;
E
Eduardo Otubo 已提交
3010 3011 3012 3013

    /*Getting the interface mac */
    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
3014
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
3015

3016
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3017 3018 3019
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F lpar_id,slot_num,mac_addr|"
                      " sed -n '/%d,%d/ s/^.*,//p'", lpar_id, slot);
3020
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
3021 3022

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
3023
        goto cleanup;
E
Eduardo Otubo 已提交
3024 3025 3026

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

3027
    result = virGetInterface(conn, name, ret);
E
Eduardo Otubo 已提交
3028

E
Eric Blake 已提交
3029
cleanup:
E
Eduardo Otubo 已提交
3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042
    VIR_FREE(ret);
    return result;
}

static int
phypInterfaceIsActive(virInterfacePtr iface)
{
    ConnectionData *connection_data = iface->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = iface->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
E
Eric Blake 已提交
3043
    int state = -1;
E
Eduardo Otubo 已提交
3044 3045 3046

    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
3047
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
3048

3049
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3050 3051 3052
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,state |"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
3053
    phypExecInt(session, &buf, iface->conn, &state);
E
Eduardo Otubo 已提交
3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070
    return state;
}

static int
phypListInterfaces(virConnectPtr conn, char **const names, int nnames)
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    int exit_status = 0;
    int got = 0;
    int i;
    char *ret = NULL;
    char *networks = NULL;
E
Eric Blake 已提交
3071
    char *char_ptr = NULL;
E
Eduardo Otubo 已提交
3072
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
3073
    bool success = false;
E
Eduardo Otubo 已提交
3074 3075 3076

    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
3077 3078
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype slot  --level slot|"
E
Eduardo Otubo 已提交
3079 3080
                      " sed '/eth/!d; /lpar_id=%d/d; s/^.*drc_name=//g'",
                      vios_id);
3081
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
3082

E
Eric Blake 已提交
3083 3084
    /* I need to parse the textual return in order to get the network
     * interfaces */
E
Eduardo Otubo 已提交
3085
    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
3086
        goto cleanup;
E
Eduardo Otubo 已提交
3087 3088 3089 3090

    networks = ret;

    while (got < nnames) {
E
Eric Blake 已提交
3091
        char_ptr = strchr(networks, '\n');
E
Eduardo Otubo 已提交
3092

E
Eric Blake 已提交
3093 3094
        if (char_ptr) {
            *char_ptr = '\0';
E
Eduardo Otubo 已提交
3095 3096
            if ((names[got++] = strdup(networks)) == NULL) {
                virReportOOMError();
E
Eric Blake 已提交
3097
                goto cleanup;
E
Eduardo Otubo 已提交
3098
            }
E
Eric Blake 已提交
3099 3100
            char_ptr++;
            networks = char_ptr;
E
Eduardo Otubo 已提交
3101 3102 3103 3104 3105
        } else {
            break;
        }
    }

E
Eric Blake 已提交
3106 3107 3108 3109 3110
cleanup:
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);
    }
E
Eduardo Otubo 已提交
3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123
    VIR_FREE(ret);
    return got;
}

static int
phypNumOfInterfaces(virConnectPtr conn)
{
    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 system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
E
Eric Blake 已提交
3124
    int nnets = -1;
E
Eduardo Otubo 已提交
3125 3126 3127 3128
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "lshwres ");
    if (system_type == HMC)
3129
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
3130

3131
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3132 3133
                      "-r virtualio --rsubtype eth --level lpar|"
                      "grep -v lpar_id=%d|grep -c lpar_name", vios_id);
E
Eric Blake 已提交
3134
    phypExecInt(session, &buf, conn, &nnets);
E
Eduardo Otubo 已提交
3135 3136 3137
    return nnets;
}

3138 3139
static int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
3140
{
3141
    ConnectionData *connection_data = conn->networkPrivateData;
3142
    phyp_driverPtr phyp_driver = conn->privateData;
3143 3144 3145 3146 3147 3148 3149
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    char *managed_system = phyp_driver->managed_system;
    int state = VIR_DOMAIN_NOSTATE;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3150

3151 3152
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3153 3154
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F state --filter lpar_ids=%d", lpar_id);
3155
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3156

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

3160 3161 3162 3163 3164 3165
    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;
3166

3167
cleanup:
3168 3169
    VIR_FREE(ret);
    return state;
3170 3171
}

3172 3173 3174 3175
/* XXX - is this needed? */
static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED;
static int
phypDiskType(virConnectPtr conn, char *backing_device)
3176 3177
{
    phyp_driverPtr phyp_driver = conn->privateData;
3178 3179 3180 3181 3182 3183 3184 3185 3186
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    int disk_type = -1;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3187

3188 3189
    virBufferAddLit(&buf, "viosvrcmd");
    if (system_type == HMC)
3190 3191
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -p %d -c \"lssp -field name type "
E
Eric Blake 已提交
3192
                      "-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"",
3193
                      vios_id, backing_device);
3194
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3195

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

3199 3200 3201 3202
    if (STREQ(ret, "LVPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_BLOCK;
    else if (STREQ(ret, "FBPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_FILE;
3203

3204
cleanup:
3205 3206 3207
    VIR_FREE(ret);
    return disk_type;
}
3208

3209 3210 3211 3212 3213
static int
phypNumDefinedDomains(virConnectPtr conn)
{
    return phypNumDomainsGeneric(conn, 1);
}
3214

3215 3216 3217 3218
static int
phypNumDomains(virConnectPtr conn)
{
    return phypNumDomainsGeneric(conn, 0);
3219 3220
}

3221 3222
static int
phypListDomains(virConnectPtr conn, int *ids, int nids)
3223
{
3224 3225
    return phypListDomainsGeneric(conn, ids, nids, 0);
}
3226

3227 3228 3229
static int
phypListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
{
3230
    bool success = false;
3231 3232 3233 3234 3235 3236 3237 3238 3239 3240
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    int got = 0;
    int i;
    char *ret = NULL;
    char *domains = NULL;
E
Eric Blake 已提交
3241
    char *char_ptr = NULL;
3242
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3243

3244 3245
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3246 3247
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F name,state"
E
Eric Blake 已提交
3248
                      "|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'");
3249
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3250

3251 3252
    /* I need to parse the textual return in order to get the domains */
    if (exit_status < 0 || ret == NULL)
3253
        goto cleanup;
3254 3255
    else {
        domains = ret;
3256

3257
        while (got < nnames) {
E
Eric Blake 已提交
3258
            char_ptr = strchr(domains, '\n');
3259

E
Eric Blake 已提交
3260 3261
            if (char_ptr) {
                *char_ptr = '\0';
3262
                if ((names[got++] = strdup(domains)) == NULL) {
3263
                    virReportOOMError();
3264
                    goto cleanup;
3265
                }
E
Eric Blake 已提交
3266 3267
                char_ptr++;
                domains = char_ptr;
3268 3269
            } else
                break;
3270
        }
3271 3272
    }

3273 3274
    success = true;

3275
cleanup:
3276 3277 3278 3279 3280 3281
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);

        got = -1;
    }
3282
    VIR_FREE(ret);
3283
    return got;
3284 3285
}

3286 3287
static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
3288
{
3289 3290 3291 3292 3293 3294 3295
    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];
3296

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

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

3304 3305 3306 3307 3308 3309
    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
3310 3311
}

3312 3313
static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
3314 3315
{
    ConnectionData *connection_data = conn->networkPrivateData;
3316
    phyp_driverPtr phyp_driver = conn->privateData;
3317
    LIBSSH2_SESSION *session = connection_data->session;
3318 3319 3320 3321
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];
E
Eduardo Otubo 已提交
3322

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

3326
    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
3327
        goto cleanup;
3328

3329
    if (exit_status < 0)
3330
        goto cleanup;
3331

3332
    dom = virGetDomain(conn, lpar_name, lpar_uuid);
3333

3334 3335
    if (dom)
        dom->id = lpar_id;
3336

3337
cleanup:
3338
    VIR_FREE(lpar_name);
3339

3340
    return dom;
3341 3342
}

3343
static char *
3344
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3345
{
3346 3347
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3348
    LIBSSH2_SESSION *session = connection_data->session;
3349 3350
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;
E
Eduardo Otubo 已提交
3351

3352 3353
    /* Flags checked by virDomainDefFormat */

3354
    memset(&def, 0, sizeof(virDomainDef));
E
Eduardo Otubo 已提交
3355

3356 3357 3358 3359 3360 3361 3362
    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) {
3363
        VIR_ERROR(_("Unable to determine domain's name."));
3364
        goto err;
E
Eduardo Otubo 已提交
3365 3366
    }

3367
    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
3368
        VIR_ERROR(_("Unable to generate random uuid."));
E
Eduardo Otubo 已提交
3369 3370
        goto err;
    }
3371

3372
    if ((def.mem.max_balloon =
3373
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
3374
        VIR_ERROR(_("Unable to determine domain's max memory."));
3375 3376
        goto err;
    }
3377

3378
    if ((def.mem.cur_balloon =
3379
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
3380
        VIR_ERROR(_("Unable to determine domain's memory."));
3381 3382
        goto err;
    }
3383

E
Eric Blake 已提交
3384
    if ((def.maxvcpus = def.vcpus =
3385
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
3386
        VIR_ERROR(_("Unable to determine domain's CPU."));
3387
        goto err;
3388
    }
3389

3390
    return virDomainDefFormat(&def, flags);
3391

3392
err:
3393 3394
    return NULL;
}
3395

3396 3397 3398
static int
phypDomainResume(virDomainPtr dom)
{
3399
    int result = -1;
3400 3401 3402 3403 3404 3405 3406 3407
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3408

3409 3410
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3411 3412
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
3413
                      dom->id, dom->name);
3414
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3415

3416
    if (exit_status < 0)
3417
        goto cleanup;
3418

3419
    result = 0;
3420

3421
cleanup:
3422
    VIR_FREE(ret);
3423 3424

    return result;
3425 3426
}

3427
static int
E
Eric Blake 已提交
3428
phypDomainReboot(virDomainPtr dom, unsigned int flags)
3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440
{
    int result = -1;
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    virConnectPtr conn = dom->conn;
    LIBSSH2_SESSION *session = connection_data->session;
    phyp_driverPtr phyp_driver = conn->privateData;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

E
Eric Blake 已提交
3441 3442
    virCheckFlags(0, -1);

3443 3444
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3445 3446
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461
                      " -r lpar -o shutdown --id %d --immed --restart",
                      dom->id);
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);

    if (exit_status < 0)
        goto cleanup;

    result = 0;

  cleanup:
    VIR_FREE(ret);

    return result;
}

3462 3463
static int
phypDomainShutdown(virDomainPtr dom)
3464
{
3465
    int result = -1;
3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    virConnectPtr conn = dom->conn;
    LIBSSH2_SESSION *session = connection_data->session;
    phyp_driverPtr phyp_driver = conn->privateData;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3478 3479
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o shutdown --id %d", dom->id);
3480
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3481 3482

    if (exit_status < 0)
3483
        goto cleanup;
3484

3485
    result = 0;
3486

3487
cleanup:
3488
    VIR_FREE(ret);
3489 3490

    return result;
3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502
}

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)
3503
        VIR_WARN("Unable to determine domain's max memory.");
3504 3505 3506

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

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

    return 0;
}

3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530
static int
phypDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virCheckFlags(0, -1);

    *state = phypGetLparState(dom->conn, dom->id);
    if (reason)
        *reason = 0;

    return 0;
}

3531
static int
3532 3533
phypDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
3534
{
3535
    int result = -1;
3536 3537 3538 3539 3540 3541 3542 3543 3544
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

3545 3546
    virCheckFlags(0, -1);

3547 3548
    virBufferAddLit(&buf, "rmsyscfg");
    if (system_type == HMC)
3549 3550
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
3551
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3552 3553

    if (exit_status < 0)
3554
        goto cleanup;
3555 3556

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
3557
        goto cleanup;
3558

3559
    dom->id = -1;
3560
    result = 0;
3561

3562
cleanup:
3563 3564
    VIR_FREE(ret);

3565
    return result;
3566
}
3567

3568 3569 3570 3571 3572 3573
static int
phypDomainDestroy(virDomainPtr dom)
{
    return phypDomainDestroyFlags(dom, 0);
}

3574 3575
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
3576
{
3577
    int result = -1;
3578 3579 3580 3581 3582 3583 3584 3585
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3586

3587
    if (!def->mem.cur_balloon) {
3588 3589 3590
        PHYP_ERROR(VIR_ERR_XML_ERROR, "%s",
                _("Field <memory> on the domain XML file is missing or has "
                  "invalid value."));
3591
        goto cleanup;
3592 3593
    }

3594
    if (!def->mem.max_balloon) {
3595 3596 3597
        PHYP_ERROR(VIR_ERR_XML_ERROR, "%s",
                _("Field <currentMemory> on the domain XML file is missing or "
                  "has invalid value."));
3598
        goto cleanup;
3599 3600
    }

3601 3602
    if (def->ndisks < 1) {
        PHYP_ERROR(VIR_ERR_XML_ERROR, "%s",
3603
                   _("Domain XML must contain at least one <disk> element."));
3604
        goto cleanup;
3605 3606 3607
    }

    if (!def->disks[0]->src) {
3608 3609
        PHYP_ERROR(VIR_ERR_XML_ERROR, "%s",
                   _("Field <src> under <disk> on the domain XML file is "
3610
                     "missing."));
3611
        goto cleanup;
3612 3613
    }

3614 3615
    virBufferAddLit(&buf, "mksyscfg");
    if (system_type == HMC)
3616
        virBufferAsprintf(&buf, " -m %s", managed_system);
3617 3618 3619 3620
    virBufferAsprintf(&buf, " -r lpar -p %s -i min_mem=%lld,desired_mem=%lld,"
                      "max_mem=%lld,desired_procs=%d,virtual_scsi_adapters=%s",
                      def->name, def->mem.cur_balloon,
                      def->mem.cur_balloon, def->mem.max_balloon,
3621
                      (int) def->vcpus, def->disks[0]->src);
3622
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3623

3624
    if (exit_status < 0) {
3625
        VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
3626
        goto cleanup;
3627
    }
3628

3629
    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
3630
        VIR_ERROR(_("Unable to add LPAR to the table"));
3631
        goto cleanup;
3632
    }
3633

3634
    result = 0;
3635

3636
cleanup:
3637
    VIR_FREE(ret);
3638 3639

    return result;
3640
}
3641

3642 3643 3644 3645
static virDomainPtr
phypDomainCreateAndStart(virConnectPtr conn,
                         const char *xml, unsigned int flags)
{
E
Eduardo Otubo 已提交
3646
    virCheckFlags(0, NULL);
3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660

    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;

    virCheckFlags(0, NULL);

    if (!(def = virDomainDefParseString(phyp_driver->caps, xml,
M
Matthias Bolte 已提交
3661
                                        1 << VIR_DOMAIN_VIRT_PHYP,
3662 3663 3664 3665
                                        VIR_DOMAIN_XML_SECURE)))
        goto err;

    /* checking if this name already exists on this system */
3666
    if (phypGetLparID(session, managed_system, def->name, conn) != -1) {
3667
        VIR_WARN("LPAR name already exists.");
3668 3669 3670 3671 3672 3673
        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) {
3674
            VIR_WARN("LPAR ID or UUID already exists.");
3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689
            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;

3690
err:
3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
    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;
}

static int
3710 3711
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724
{
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    char *ret = NULL;
    char operation;
    unsigned long ncpus = 0;
    unsigned int amount = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

3725 3726 3727 3728 3729
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
        PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
        return -1;
    }

3730 3731 3732 3733
    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        return 0;

    if (nvcpus > phypGetLparCPUMAX(dom)) {
3734
        VIR_ERROR(_("You are trying to set a number of CPUs bigger than "
3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
                     "the max possible."));
        return 0;
    }

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

    virBufferAddLit(&buf, "chhwres -r proc");
    if (system_type == HMC)
3750 3751
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --id %d -o %c --procunits %d 2>&1 |sed "
3752 3753
                      "-e 's/^.*\\([0-9][0-9]*.[0-9][0-9]*\\).*$/\\1/'",
                      dom->id, operation, amount);
3754
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3755 3756

    if (exit_status < 0) {
3757
        VIR_ERROR(_
3758 3759 3760 3761 3762 3763
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    " Contact your support to enable this feature."));
    }

    VIR_FREE(ret);
    return 0;
3764 3765

}
3766

3767 3768 3769 3770 3771 3772
static int
phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus)
{
    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

3773
static virDrvOpenStatus
3774 3775
phypVIOSDriverOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
3776
                   unsigned int flags)
3777
{
E
Eric Blake 已提交
3778 3779
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

3780 3781 3782
    if (conn->driver->no != VIR_DRV_PHYP)
        return VIR_DRV_OPEN_DECLINED;

3783 3784 3785 3786
    return VIR_DRV_OPEN_SUCCESS;
}

static int
3787
phypVIOSDriverClose(virConnectPtr conn ATTRIBUTE_UNUSED)
3788 3789 3790 3791
{
    return 0;
}

3792
static virDriver phypDriver = {
3793 3794
    .no = VIR_DRV_PHYP,
    .name = "PHYP",
3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806
    .open = phypOpen, /* 0.7.0 */
    .close = phypClose, /* 0.7.0 */
    .getCapabilities = phypConnectGetCapabilities, /* 0.7.3 */
    .listDomains = phypListDomains, /* 0.7.0 */
    .numOfDomains = phypNumDomains, /* 0.7.0 */
    .domainCreateXML = phypDomainCreateAndStart, /* 0.7.3 */
    .domainLookupByID = phypDomainLookupByID, /* 0.7.0 */
    .domainLookupByName = phypDomainLookupByName, /* 0.7.0 */
    .domainResume = phypDomainResume, /* 0.7.0 */
    .domainShutdown = phypDomainShutdown, /* 0.7.0 */
    .domainReboot = phypDomainReboot, /* 0.9.1 */
    .domainDestroy = phypDomainDestroy, /* 0.7.3 */
3807
    .domainDestroyFlags = phypDomainDestroyFlags, /* 0.9.4 */
3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820
    .domainGetInfo = phypDomainGetInfo, /* 0.7.0 */
    .domainGetState = phypDomainGetState, /* 0.9.2 */
    .domainSetVcpus = phypDomainSetCPU, /* 0.7.3 */
    .domainSetVcpusFlags = phypDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = phypDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = phypGetLparCPUMAX, /* 0.7.3 */
    .domainGetXMLDesc = phypDomainGetXMLDesc, /* 0.7.0 */
    .listDefinedDomains = phypListDefinedDomains, /* 0.7.0 */
    .numOfDefinedDomains = phypNumDefinedDomains, /* 0.7.0 */
    .domainAttachDevice = phypAttachDevice, /* 0.8.2 */
    .isEncrypted = phypIsEncrypted, /* 0.7.3 */
    .isSecure = phypIsSecure, /* 0.7.3 */
    .domainIsUpdated = phypIsUpdated, /* 0.8.6 */
3821
    .isAlive = phypIsAlive, /* 0.9.8 */
3822 3823
};

3824 3825
static virStorageDriver phypStorageDriver = {
    .name = "PHYP",
3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843
    .open = phypVIOSDriverOpen, /* 0.8.2 */
    .close = phypVIOSDriverClose, /* 0.8.2 */

    .numOfPools = phypNumOfStoragePools, /* 0.8.2 */
    .listPools = phypListStoragePools, /* 0.8.2 */
    .poolLookupByName = phypStoragePoolLookupByName, /* 0.8.2 */
    .poolLookupByUUID = phypGetStoragePoolLookUpByUUID, /* 0.8.2 */
    .poolCreateXML = phypStoragePoolCreateXML, /* 0.8.2 */
    .poolDestroy = phypDestroyStoragePool, /* 0.8.2 */
    .poolGetXMLDesc = phypGetStoragePoolXMLDesc, /* 0.8.2 */
    .poolNumOfVolumes = phypStoragePoolNumOfVolumes, /* 0.8.2 */
    .poolListVolumes = phypStoragePoolListVolumes, /* 0.8.2 */

    .volLookupByName = phypVolumeLookupByName, /* 0.8.2 */
    .volLookupByPath = phypVolumeLookupByPath, /* 0.8.2 */
    .volCreateXML = phypStorageVolCreateXML, /* 0.8.2 */
    .volGetXMLDesc = phypVolumeGetXMLDesc, /* 0.8.2 */
    .volGetPath = phypVolumeGetPath, /* 0.8.2 */
3844 3845
};

E
Eduardo Otubo 已提交
3846
static virInterfaceDriver phypInterfaceDriver = {
3847
    .name = "PHYP",
3848 3849 3850 3851 3852 3853 3854 3855
    .open = phypVIOSDriverOpen, /* 0.9.1 */
    .close = phypVIOSDriverClose, /* 0.9.1 */
    .numOfInterfaces = phypNumOfInterfaces, /* 0.9.1 */
    .listInterfaces = phypListInterfaces, /* 0.9.1 */
    .interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
    .interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
    .interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
    .interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
3856 3857
};

3858 3859 3860
int
phypRegister(void)
{
3861 3862 3863 3864
    if (virRegisterDriver(&phypDriver) < 0)
        return -1;
    if (virRegisterStorageDriver(&phypStorageDriver) < 0)
        return -1;
E
Eduardo Otubo 已提交
3865
    if (virRegisterInterfaceDriver(&phypInterfaceDriver) < 0)
3866
        return -1;
3867

3868 3869
    return 0;
}