phyp_driver.c 108.0 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2013 Red Hat, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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
21
 * License along with this library.  If not, see
O
Osier Yang 已提交
22
 * <http://www.gnu.org/licenses/>.
23 24 25 26 27
 */

#include <config.h>

#include <sys/types.h>
28
#include <sys/stat.h>
29 30 31 32 33 34 35
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
36 37 38 39 40
#include <libssh2.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
41 42
#include <fcntl.h>
#include <domain_event.h>
43
#include <poll.h>
44 45

#include "internal.h"
46
#include "virauth.h"
47
#include "datatypes.h"
48
#include "virbuffer.h"
49
#include "viralloc.h"
50
#include "virlog.h"
51
#include "driver.h"
52
#include "virerror.h"
53
#include "viruuid.h"
54
#include "domain_conf.h"
55
#include "storage_conf.h"
56
#include "nodeinfo.h"
E
Eric Blake 已提交
57
#include "virfile.h"
E
Eduardo Otubo 已提交
58
#include "interface_conf.h"
59
#include "phyp_driver.h"
60
#include "virstring.h"
61 62 63

#define VIR_FROM_THIS VIR_FROM_PHYP

64 65 66
VIR_LOG_INIT("phyp.phyp_driver");


67 68 69 70
/*
 * URI: phyp://user@[hmc|ivm]/managed_system
 * */

71
static unsigned const int HMC = 0;
E
Eduardo Otubo 已提交
72
static unsigned const int PHYP_IFACENAME_SIZE = 24;
73
static unsigned const int PHYP_MAC_SIZE = 12;
74

75 76 77
static int
waitsocket(int socket_fd, LIBSSH2_SESSION * session)
{
78
    struct pollfd fds[1];
79
    int dir;
80

81 82
    memset(fds, 0, sizeof(fds));
    fds[0].fd = socket_fd;
83

84 85
    /* now make sure we wait in the correct direction */
    dir = libssh2_session_block_directions(session);
86

87
    if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
88
        fds[0].events |= POLLIN;
89

90
    if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
91
        fds[0].events |= POLLOUT;
92

93
    return poll(fds, ARRAY_CARDINALITY(fds), -1);
94
}
95

96 97
/* this function is the layer that manipulates the ssh channel itself
 * and executes the commands on the remote machine */
98 99 100
static char *phypExec(LIBSSH2_SESSION *, const char *, int *, virConnectPtr)
    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
    ATTRIBUTE_NONNULL(4);
101
static char *
102
phypExec(LIBSSH2_SESSION *session, const char *cmd, int *exit_status,
103 104 105 106 107
         virConnectPtr conn)
{
    LIBSSH2_CHANNEL *channel;
    ConnectionData *connection_data = conn->networkPrivateData;
    virBuffer tex_ret = VIR_BUFFER_INITIALIZER;
108 109
    char *buffer = NULL;
    size_t buffer_size = 16384;
110 111 112 113
    int exitcode;
    int bytecount = 0;
    int sock = connection_data->sock;
    int rc = 0;
114

115
    if (VIR_ALLOC_N(buffer, buffer_size) < 0)
116 117
        return NULL;

118 119 120 121
    /* 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) {
122 123 124 125 126
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
127 128
    }

129 130
    if (channel == NULL) {
        goto err;
131
    }
132

133 134
    while ((rc = libssh2_channel_exec(channel, cmd)) ==
           LIBSSH2_ERROR_EAGAIN) {
135 136 137 138 139
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
140
    }
141

142 143 144
    if (rc != 0) {
        goto err;
    }
145

146 147 148
    for (;;) {
        /* loop until we block */
        do {
149
            rc = libssh2_channel_read(channel, buffer, buffer_size);
150 151
            if (rc > 0) {
                bytecount += rc;
152
                virBufferAdd(&tex_ret, buffer, -1);
153 154 155
            }
        }
        while (rc > 0);
156

157 158 159
        /* this is due to blocking that would occur otherwise so we loop on
         * this condition */
        if (rc == LIBSSH2_ERROR_EAGAIN) {
160 161 162 163 164
            if (waitsocket(sock, session) < 0 && errno != EINTR) {
                virReportSystemError(errno, "%s",
                                     _("unable to wait on libssh2 socket"));
                goto err;
            }
165 166 167
        } else {
            break;
        }
E
Eduardo Otubo 已提交
168 169
    }

170
    exitcode = 127;
171

172
    while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) {
173 174 175 176 177
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
178 179
    }

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

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

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

err:
    (*exit_status) = SSH_CMD_ERR;
    virBufferFreeAndReset(&tex_ret);
    VIR_FREE(buffer);
    return NULL;
201 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
/* 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 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/* 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;
}

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

261
    ret = phypExec(session, "lshmc -V", &exit_status, conn);
262

263 264
    VIR_FREE(ret);
    return exit_status;
265 266
}

267
static int
268
phypGetVIOSPartitionID(virConnectPtr conn)
269
{
270 271 272 273 274 275 276
    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;
277

278 279
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
280
        virBufferAsprintf(&buf, " -m %s", managed_system);
E
Eric Blake 已提交
281 282
    virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env"
                    "|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'");
E
Eric Blake 已提交
283
    phypExecInt(session, &buf, conn, &id);
284
    return id;
285
}
286

287

288 289 290 291 292
static virCapsPtr
phypCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;
293

294 295
    if ((caps = virCapabilitiesNew(virArchFromHost(),
                                   0, 0)) == NULL)
296
        goto no_memory;
297

298 299 300 301 302 303
    /* 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);
304
        VIR_WARN
305
            ("Failed to query host NUMA topology, disabling NUMA capabilities");
306 307
    }

308 309
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "linux",
310
                                         caps->host.arch,
311 312
                                         NULL, NULL, 0, NULL)) == NULL)
        goto no_memory;
313

314 315 316
    if (virCapabilitiesAddGuestDomain(guest,
                                      "phyp", NULL, NULL, 0, NULL) == NULL)
        goto no_memory;
317

318
    return caps;
319

320
no_memory:
321
    virObjectUnref(caps);
322 323
    return NULL;
}
324

325 326 327 328 329 330 331 332 333
/* 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
334
phypConnectNumOfDomainsGeneric(virConnectPtr conn, unsigned int type)
335 336 337 338 339
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
340
    int ndom = -1;
341 342 343
    char *managed_system = phyp_driver->managed_system;
    const char *state;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
344

345 346 347 348 349 350 351
    if (type == 0)
        state = "|grep Running";
    else if (type == 1) {
        if (system_type == HMC) {
            state = "|grep \"Not Activated\"";
        } else {
            state = "|grep \"Open Firmware\"";
352
        }
353 354
    } else
        state = " ";
355

356 357
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
358 359
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9][0-9]*'",
360
                      state);
E
Eric Blake 已提交
361
    phypExecInt(session, &buf, conn, &ndom);
362
    return ndom;
363 364
}

365 366 367 368 369 370 371 372
/* 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
373 374
phypConnectListDomainsGeneric(virConnectPtr conn, int *ids, int nids,
                              unsigned int type)
375
{
376
    ConnectionData *connection_data = conn->networkPrivateData;
E
Eduardo Otubo 已提交
377
    phyp_driverPtr phyp_driver = conn->privateData;
378
    LIBSSH2_SESSION *session = connection_data->session;
E
Eduardo Otubo 已提交
379
    int system_type = phyp_driver->system_type;
380
    char *managed_system = phyp_driver->managed_system;
381
    int exit_status = 0;
382
    int got = -1;
383
    char *ret = NULL;
384
    char *line, *next_line;
385
    const char *state;
E
Eduardo Otubo 已提交
386 387
    virBuffer buf = VIR_BUFFER_INITIALIZER;

388 389 390 391 392
    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

E
Eduardo Otubo 已提交
393 394
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
395 396
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'",
397
                      state);
398
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
399

400
    if (exit_status < 0 || ret == NULL)
401
        goto cleanup;
402 403 404 405 406 407 408 409

    /* 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;
410
            goto cleanup;
411
        }
412 413 414 415
        got++;
        line = next_line;
        while (*line == '\n')
            line++; /* skip \n */
416
    }
417

418
cleanup:
419
    VIR_FREE(ret);
420
    return got;
421 422
}

423 424
static int
phypUUIDTable_WriteFile(virConnectPtr conn)
425
{
426 427
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
428
    size_t i = 0;
429 430 431 432 433
    int fd = -1;
    char local_file[] = "./uuid_table";

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

435
    for (i = 0; i < uuid_table->nlpars; i++) {
436 437 438
        if (safewrite(fd, &uuid_table->lpars[i]->id,
                      sizeof(uuid_table->lpars[i]->id)) !=
            sizeof(uuid_table->lpars[i]->id)) {
439
            VIR_ERROR(_("Unable to write information to local file."));
440 441 442 443 444
            goto err;
        }

        if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) !=
            VIR_UUID_BUFLEN) {
445
            VIR_ERROR(_("Unable to write information to local file."));
446
            goto err;
447 448 449
        }
    }

450 451 452 453 454
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
        goto err;
    }
455 456
    return 0;

457
err:
458
    VIR_FORCE_CLOSE(fd);
459 460 461
    return -1;
}

462 463
static int
phypUUIDTable_Push(virConnectPtr conn)
464 465
{
    ConnectionData *connection_data = conn->networkPrivateData;
466
    LIBSSH2_SESSION *session = connection_data->session;
467 468 469 470
    LIBSSH2_CHANNEL *channel = NULL;
    struct stat local_fileinfo;
    char buffer[1024];
    int rc = 0;
471
    FILE *f = NULL;
472 473 474 475
    size_t nread, sent;
    char *ptr;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
476
    int ret = -1;
477

478
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
479
                    NULLSTR(conn->uri->user)) < 0)
480
        goto cleanup;
481

482
    if (stat(local_file, &local_fileinfo) == -1) {
483
        VIR_WARN("Unable to stat local file.");
484
        goto cleanup;
485
    }
486

487
    if (!(f = fopen(local_file, "rb"))) {
488
        VIR_WARN("Unable to open local file.");
489
        goto cleanup;
490
    }
491

492 493 494 495 496
    do {
        channel =
            libssh2_scp_send(session, remote_file,
                             0x1FF & local_fileinfo.st_mode,
                             (unsigned long) local_fileinfo.st_size);
497

498 499
        if ((!channel) && (libssh2_session_last_errno(session) !=
                           LIBSSH2_ERROR_EAGAIN))
500
            goto cleanup;
501
    } while (!channel);
502

503
    do {
504
        nread = fread(buffer, 1, sizeof(buffer), f);
505
        if (nread <= 0) {
506
            if (feof(f)) {
507 508 509 510
                /* end of file */
                break;
            } else {
                VIR_ERROR(_("Failed to read from %s"), local_file);
511
                goto cleanup;
512 513 514 515
            }
        }
        ptr = buffer;
        sent = 0;
516

517 518 519 520 521 522 523 524 525 526 527 528 529
        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);
530

531
    ret = 0;
532

533
cleanup:
534 535 536 537 538 539 540
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
541 542
    VIR_FORCE_FCLOSE(f);
    return ret;
543 544 545
}

static int
546
phypUUIDTable_RemLpar(virConnectPtr conn, int id)
547
{
E
Eduardo Otubo 已提交
548
    phyp_driverPtr phyp_driver = conn->privateData;
549
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
550
    size_t i = 0;
E
Eduardo Otubo 已提交
551

552 553 554 555 556
    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);
        }
557 558
    }

559
    if (phypUUIDTable_WriteFile(conn) == -1)
560 561
        goto err;

562
    if (phypUUIDTable_Push(conn) == -1)
563 564
        goto err;

565
    return 0;
566

567
err:
568
    return -1;
569 570
}

571 572
static int
phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id)
573
{
E
Eduardo Otubo 已提交
574
    phyp_driverPtr phyp_driver = conn->privateData;
575
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
576
    lparPtr item = NULL;
E
Eduardo Otubo 已提交
577

578
    if (VIR_ALLOC(item) < 0)
579
        goto err;
580

581 582
    item->id = id;
    memcpy(item->uuid, uuid, VIR_UUID_BUFLEN);
583

584 585
    if (VIR_APPEND_ELEMENT_COPY(uuid_table->lpars, uuid_table->nlpars, item) < 0)
        goto err;
586

587 588
    if (phypUUIDTable_WriteFile(conn) == -1)
        goto err;
589

590
    if (phypUUIDTable_Push(conn) == -1)
591 592
        goto err;

593
    return 0;
594

595
err:
596
    VIR_FREE(item);
597
    return -1;
598 599
}

600 601
static int
phypUUIDTable_ReadFile(virConnectPtr conn)
602
{
E
Eduardo Otubo 已提交
603
    phyp_driverPtr phyp_driver = conn->privateData;
604
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
605
    size_t i = 0;
606 607 608 609
    int fd = -1;
    char local_file[] = "./uuid_table";
    int rc = 0;
    int id;
610

611
    if ((fd = open(local_file, O_RDONLY)) == -1) {
612
        VIR_WARN("Unable to read information from local file.");
613
        goto err;
614 615
    }

616 617 618
    /* 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++) {
619

620 621
            rc = read(fd, &id, sizeof(int));
            if (rc == sizeof(int)) {
622
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
623 624 625
                    goto err;
                uuid_table->lpars[i]->id = id;
            } else {
626
                VIR_WARN
627
                    ("Unable to read from information from local file.");
628 629
                goto err;
            }
630

631 632
            rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN);
            if (rc != VIR_UUID_BUFLEN) {
633
                VIR_WARN("Unable to read information from local file.");
634 635
                goto err;
            }
636
        }
637
    }
638

639
    VIR_FORCE_CLOSE(fd);
640
    return 0;
641

642
err:
643
    VIR_FORCE_CLOSE(fd);
644
    return -1;
645 646
}

647 648
static int
phypUUIDTable_Pull(virConnectPtr conn)
649 650
{
    ConnectionData *connection_data = conn->networkPrivateData;
651
    LIBSSH2_SESSION *session = connection_data->session;
652 653 654 655
    LIBSSH2_CHANNEL *channel = NULL;
    struct stat fileinfo;
    char buffer[1024];
    int rc = 0;
656
    int fd = -1;
657 658 659 660 661 662
    int got = 0;
    int amount = 0;
    int total = 0;
    int sock = 0;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
663
    int ret = -1;
E
Eduardo Otubo 已提交
664

665
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
666
                    NULLSTR(conn->uri->user)) < 0)
667
        goto cleanup;
668

669 670 671
    /* Trying to stat the remote file. */
    do {
        channel = libssh2_scp_recv(session, remote_file, &fileinfo);
672

673 674 675
        if (!channel) {
            if (libssh2_session_last_errno(session) !=
                LIBSSH2_ERROR_EAGAIN) {
676
                goto cleanup;
677
            } else {
678 679 680
                if (waitsocket(sock, session) < 0 && errno != EINTR) {
                    virReportSystemError(errno, "%s",
                                         _("unable to wait on libssh2 socket"));
681
                    goto cleanup;
682
                }
683 684 685
            }
        }
    } while (!channel);
686

687 688
    /* Creating a new data base based on remote file */
    if ((fd = creat(local_file, 0755)) == -1)
689
        goto cleanup;
690

691 692 693 694
    /* Request a file via SCP */
    while (got < fileinfo.st_size) {
        do {
            amount = sizeof(buffer);
695

696 697 698
            if ((fileinfo.st_size - got) < amount) {
                amount = fileinfo.st_size - got;
            }
E
Eduardo Otubo 已提交
699

700 701 702
            rc = libssh2_channel_read(channel, buffer, amount);
            if (rc > 0) {
                if (safewrite(fd, buffer, rc) != rc)
703
                    VIR_WARN
704
                        ("Unable to write information to local file.");
705

706 707 708 709
                got += rc;
                total += rc;
            }
        } while (rc > 0);
710

711 712 713 714
        if ((rc == LIBSSH2_ERROR_EAGAIN)
            && (got < fileinfo.st_size)) {
            /* this is due to blocking that would occur otherwise
             * so we loop on this condition */
715

716 717 718 719
            /* now we wait */
            if (waitsocket(sock, session) < 0 && errno != EINTR) {
                virReportSystemError(errno, "%s",
                                     _("unable to wait on libssh2 socket"));
720
                goto cleanup;
721
            }
722 723 724 725
            continue;
        }
        break;
    }
726 727 728
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
729
        goto cleanup;
730
    }
731

732
    ret = 0;
733

734
cleanup:
735 736 737 738 739 740 741
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
742 743
    VIR_FORCE_CLOSE(fd);
    return ret;
744 745
}

746 747
static int
phypUUIDTable_Init(virConnectPtr conn)
748
{
E
Eric Blake 已提交
749
    uuid_tablePtr uuid_table = NULL;
750 751 752 753
    phyp_driverPtr phyp_driver;
    int nids_numdomains = 0;
    int nids_listdomains = 0;
    int *ids = NULL;
754
    size_t i = 0;
E
Eric Blake 已提交
755 756
    int ret = -1;
    bool table_created = false;
E
Eduardo Otubo 已提交
757

758
    if ((nids_numdomains = phypConnectNumOfDomainsGeneric(conn, 2)) < 0)
E
Eric Blake 已提交
759
        goto cleanup;
760

761
    if (VIR_ALLOC_N(ids, nids_numdomains) < 0)
E
Eric Blake 已提交
762
        goto cleanup;
763

764
    if ((nids_listdomains =
765
         phypConnectListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0)
E
Eric Blake 已提交
766
        goto cleanup;
767

768
    /* exit early if there are no domains */
E
Eric Blake 已提交
769 770 771 772 773
    if (nids_numdomains == 0 && nids_listdomains == 0) {
        ret = 0;
        goto cleanup;
    }
    if (nids_numdomains != nids_listdomains) {
774
        VIR_ERROR(_("Unable to determine number of domains."));
E
Eric Blake 已提交
775
        goto cleanup;
776
    }
777

778 779 780
    phyp_driver = conn->privateData;
    uuid_table = phyp_driver->uuid_table;
    uuid_table->nlpars = nids_listdomains;
781

782 783 784
    /* 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 已提交
785
        table_created = true;
786 787
        if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
            for (i = 0; i < uuid_table->nlpars; i++) {
788
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
E
Eric Blake 已提交
789
                    goto cleanup;
790
                uuid_table->lpars[i]->id = ids[i];
791

792 793 794 795
                if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0)
                    VIR_WARN("Unable to generate UUID for domain %d",
                             ids[i]);
            }
796
        } else
E
Eric Blake 已提交
797
            goto cleanup;
798

799
        if (phypUUIDTable_WriteFile(conn) == -1)
E
Eric Blake 已提交
800
            goto cleanup;
801

802
        if (phypUUIDTable_Push(conn) == -1)
E
Eric Blake 已提交
803
            goto cleanup;
804 805
    } else {
        if (phypUUIDTable_ReadFile(conn) == -1)
E
Eric Blake 已提交
806
            goto cleanup;
807
    }
808

E
Eric Blake 已提交
809
    ret = 0;
810

E
Eric Blake 已提交
811 812 813 814 815 816 817
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);
    }
818
    VIR_FREE(ids);
E
Eric Blake 已提交
819
    return ret;
820 821
}

822 823
static void
phypUUIDTable_Free(uuid_tablePtr uuid_table)
824
{
825
    size_t i;
826

827 828 829 830 831 832 833 834
    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);
835 836
}

837 838 839 840 841 842 843 844
#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)
845
{
846
    size_t len = strlen(src);
847 848
    size_t i = 0;

849
    if (len == 0)
850
        return false;
851

852 853
    for (i = 0; i < len; i++) {
        switch (src[i]) {
854 855 856 857
        SPECIALCHARACTER_CASES
            return true;
        default:
            continue;
858 859 860
        }
    }

861 862
    return false;
}
863

864 865 866 867 868 869 870 871 872 873
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;

874
    if (VIR_ALLOC_N(dst, len + 1) < 0)
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
        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;
890 891
}

892 893 894
static LIBSSH2_SESSION *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
               int *internal_socket)
895
{
896 897 898 899
    LIBSSH2_SESSION *session;
    const char *hostname = conn->uri->server;
    char *username = NULL;
    char *password = NULL;
900
    int sock = -1;
901 902 903 904 905 906
    int rc;
    struct addrinfo *ai = NULL, *cur;
    struct addrinfo hints;
    int ret;
    char *pubkey = NULL;
    char *pvtkey = NULL;
907
    char *userhome = virGetUserDirectory();
908
    struct stat pvt_stat, pub_stat;
909

910 911
    if (userhome == NULL)
        goto err;
E
Eduardo Otubo 已提交
912

913
    if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0)
914
        goto err;
915

916
    if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0)
917 918
        goto err;

919
    if (conn->uri->user != NULL) {
920
        if (VIR_STRDUP(username, conn->uri->user) < 0)
921 922 923
            goto err;
    } else {
        if (auth == NULL || auth->cb == NULL) {
924 925
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
926 927
            goto err;
        }
928

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

931
        if (username == NULL) {
932 933
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Username request failed"));
934 935 936
            goto err;
        }
    }
937

938 939 940 941
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
942

943 944
    ret = getaddrinfo(hostname, "22", &hints, &ai);
    if (ret != 0) {
945 946
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Error while getting %s address info"), hostname);
947 948
        goto err;
    }
949

950 951 952 953 954 955 956
    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;
            }
957
            VIR_FORCE_CLOSE(sock);
958 959 960
        }
        cur = cur->ai_next;
    }
961

962 963
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to connect to %s"), hostname);
964 965
    freeaddrinfo(ai);
    goto err;
966

967
connected:
968

969
    (*internal_socket) = sock;
970

971 972 973
    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
974 975
        goto err;

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

979
    while ((rc = libssh2_session_startup(session, sock)) ==
980
           LIBSSH2_ERROR_EAGAIN);
981
    if (rc) {
982 983
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failure establishing SSH session."));
984 985
        goto disconnect;
    }
986

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

993 994 995 996 997
    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
998
           LIBSSH2_ERROR_EAGAIN);
999

1000
keyboard_interactive:
1001 1002 1003 1004
    if (rc == LIBSSH2_ERROR_SOCKET_NONE
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
        if (auth == NULL || auth->cb == NULL) {
1005 1006
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
1007 1008
            goto disconnect;
        }
1009

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

1012
        if (password == NULL) {
1013 1014
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Password request failed"));
1015 1016
            goto disconnect;
        }
1017

1018 1019 1020
        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
1021
               LIBSSH2_ERROR_EAGAIN);
1022

1023
        if (rc) {
1024 1025
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("Authentication failed"));
1026 1027 1028
            goto disconnect;
        } else
            goto exit;
1029

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

1033 1034
    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
1035 1036 1037
        goto err;
    }

1038
disconnect:
1039 1040
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1041
err:
1042
    VIR_FORCE_CLOSE(sock);
1043 1044 1045 1046 1047
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
1048
    return NULL;
1049

1050
exit:
1051 1052 1053 1054 1055 1056
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return session;
1057 1058
}

1059
static virDrvOpenStatus
1060 1061
phypConnectOpen(virConnectPtr conn,
                virConnectAuthPtr auth, unsigned int flags)
1062 1063 1064 1065 1066 1067 1068 1069
{
    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 已提交
1070

E
Eric Blake 已提交
1071 1072
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1073 1074 1075 1076 1077 1078 1079
    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) {
1080 1081
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing server name in phyp:// URI"));
1082 1083 1084
        return VIR_DRV_OPEN_ERROR;
    }

1085
    if (VIR_ALLOC(phyp_driver) < 0)
1086
        goto failure;
1087

1088
    if (VIR_ALLOC(uuid_table) < 0)
1089
        goto failure;
1090

1091
    if (VIR_ALLOC(connection_data) < 0)
1092
        goto failure;
1093
    connection_data->sock = -1;
1094

1095 1096
    if (conn->uri->path) {
        /* need to shift one byte in order to remove the first "/" of URI component */
1097 1098
        if (VIR_STRDUP(managed_system,
                       conn->uri->path + (conn->uri->path[0] == '/')) < 0)
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
            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';

1109
        if (contains_specialcharacters(conn->uri->path)) {
1110 1111 1112
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s",
                           _("Error parsing 'path'. Invalid characters."));
1113 1114 1115 1116 1117
            goto failure;
        }
    }

    if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
1118 1119
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Error while opening SSH session."));
1120 1121 1122 1123
        goto failure;
    }

    connection_data->session = session;
1124
    connection_data->sock = internal_socket;
1125 1126 1127 1128 1129 1130 1131 1132

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

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

    phyp_driver->uuid_table = uuid_table;
1133
    if ((phyp_driver->caps = phypCapsInit()) == NULL)
1134
        goto failure;
1135

1136
    if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)))
1137 1138
        goto failure;

1139 1140
    conn->privateData = phyp_driver;
    conn->networkPrivateData = connection_data;
1141

1142 1143
    if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
        goto failure;
1144

1145 1146
    if (phypUUIDTable_Init(conn) == -1)
        goto failure;
1147

1148 1149 1150 1151 1152 1153 1154
    if (phyp_driver->system_type == HMC) {
        if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
            goto failure;
    }

    return VIR_DRV_OPEN_SUCCESS;

1155
failure:
1156 1157
    VIR_FREE(managed_system);

1158
    if (phyp_driver != NULL) {
1159
        virObjectUnref(phyp_driver->caps);
1160
        virObjectUnref(phyp_driver->xmlopt);
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
        VIR_FREE(phyp_driver);
    }

    phypUUIDTable_Free(uuid_table);

    if (session != NULL) {
        libssh2_session_disconnect(session, "Disconnecting...");
        libssh2_session_free(session);
    }

1171 1172
    if (connection_data)
        VIR_FORCE_CLOSE(connection_data->sock);
1173 1174 1175
    VIR_FREE(connection_data);

    return VIR_DRV_OPEN_ERROR;
1176 1177 1178
}

static int
1179
phypConnectClose(virConnectPtr conn)
1180
{
1181 1182 1183
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
1184

1185 1186
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1187

1188
    virObjectUnref(phyp_driver->caps);
1189
    virObjectUnref(phyp_driver->xmlopt);
1190 1191 1192
    phypUUIDTable_Free(phyp_driver->uuid_table);
    VIR_FREE(phyp_driver->managed_system);
    VIR_FREE(phyp_driver);
1193 1194

    VIR_FORCE_CLOSE(connection_data->sock);
1195 1196 1197
    VIR_FREE(connection_data);
    return 0;
}
1198 1199


1200
static int
1201
phypConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1202 1203 1204 1205
{
    /* Phyp uses an SSH tunnel, so is always encrypted */
    return 1;
}
1206

1207 1208

static int
1209
phypConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1210 1211 1212
{
    /* Phyp uses an SSH tunnel, so is always secure */
    return 1;
1213 1214
}

1215 1216

static int
1217
phypConnectIsAlive(virConnectPtr conn)
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
{
    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;
}


1232
static int
1233
phypDomainIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
1234 1235 1236
{
    return 0;
}
1237 1238

/* return the lpar_id given a name and a managed system name */
1239
static int
1240 1241
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
1242
{
1243
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1244
    int system_type = phyp_driver->system_type;
1245
    int lpar_id = -1;
E
Eduardo Otubo 已提交
1246 1247
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1248
    virBufferAddLit(&buf, "lssyscfg -r lpar");
E
Eduardo Otubo 已提交
1249
    if (system_type == HMC)
1250 1251
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_names=%s -F lpar_id", name);
E
Eric Blake 已提交
1252
    phypExecInt(session, &buf, conn, &lpar_id);
1253
    return lpar_id;
1254 1255
}

1256 1257 1258 1259
/* 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)
1260 1261
{
    phyp_driverPtr phyp_driver = conn->privateData;
1262 1263 1264 1265
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1266

1267 1268
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
1269 1270
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_ids=%d -F name", lpar_id);
1271
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1272

1273
    if (exit_status < 0)
1274 1275
        VIR_FREE(ret);
    return ret;
1276 1277
}

1278 1279 1280 1281 1282 1283 1284 1285 1286

/* 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)
1287 1288
{
    phyp_driverPtr phyp_driver = conn->privateData;
1289 1290
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
1291
    size_t i = 0;
1292

1293 1294
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
1295
            memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
1296 1297 1298
            return 0;
        }
    }
1299

1300
    return -1;
1301 1302
}

1303 1304 1305 1306 1307 1308 1309 1310
/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
static unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
1311
{
1312 1313 1314 1315 1316 1317
    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;
1318

1319 1320
    if (type != 1 && type != 0)
        return 0;
1321

1322 1323
    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1324 1325
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1326 1327
                      " -r mem --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_mem" : "curr_max_mem", lpar_id);
E
Eric Blake 已提交
1328
    phypExecInt(session, &buf, conn, &memory);
1329
    return memory;
1330 1331
}

1332 1333 1334
static unsigned long
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
1335
{
1336
    ConnectionData *connection_data = conn->networkPrivateData;
1337
    LIBSSH2_SESSION *session = connection_data->session;
1338
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1339
    int system_type = phyp_driver->system_type;
1340
    int vcpus = 0;
E
Eduardo Otubo 已提交
1341
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1342

1343
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1344
    if (system_type == HMC)
1345 1346
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1347 1348
                      " -r proc --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_max_procs" : "curr_procs", lpar_id);
E
Eric Blake 已提交
1349
    phypExecInt(session, &buf, conn, &vcpus);
1350
    return vcpus;
1351
}
1352

1353 1354 1355 1356
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
    return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
1357 1358
}

1359
static int
1360
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
1361 1362 1363
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;
1364

1365
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1366
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1367 1368 1369
        return -1;
    }

1370 1371 1372
    return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}

1373
static int
1374
phypDomainGetMaxVcpus(virDomainPtr dom)
1375 1376 1377 1378 1379
{
    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1380 1381 1382
static int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
1383
{
1384 1385
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1386
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1387
    int system_type = phyp_driver->system_type;
1388
    int remote_slot = -1;
E
Eduardo Otubo 已提交
1389 1390
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1391
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1392
    if (system_type == HMC)
1393 1394
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1395
                      "remote_slot_num --filter lpar_names=%s", lpar_name);
E
Eric Blake 已提交
1396
    phypExecInt(session, &buf, conn, &remote_slot);
1397
    return remote_slot;
1398 1399
}

1400 1401 1402 1403 1404 1405
/* 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)
1406
{
1407 1408
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1409
    phyp_driverPtr phyp_driver = conn->privateData;
1410 1411 1412 1413 1414 1415 1416
    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;
1417

1418 1419 1420 1421 1422 1423
    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        return NULL;

    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1424 1425
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1426
                      "backing_devices --filter slots=%d", remote_slot);
1427
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1428

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

1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
    /* 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
1446
            goto cleanup;
1447

1448
        if (VIR_STRDUP(backing_device, char_ptr) < 0)
1449
            goto cleanup;
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
    } else {
        backing_device = ret;
        ret = NULL;
    }

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

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

1460
cleanup:
1461
    VIR_FREE(ret);
1462

1463
    return backing_device;
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
}

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)
1480 1481
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1482 1483
                      " -r prof --filter lpar_ids=%d -F name|head -n 1",
                      lpar_id);
1484
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1485

1486
    if (exit_status < 0)
1487 1488
        VIR_FREE(ret);
    return ret;
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
}

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;
1501
    int slot = -1;
1502 1503 1504
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1505
        VIR_ERROR(_("Unable to get VIOS profile name."));
1506
        return -1;
1507 1508 1509 1510 1511
    }

    virBufferAddLit(&buf, "lssyscfg");

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

1514
    virBufferAsprintf(&buf, " -r prof --filter "
1515 1516 1517 1518 1519
                      "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 已提交
1520 1521 1522
    if (phypExecInt(session, &buf, conn, &slot) < 0)
        return -1;
    return slot + 1;
1523 1524 1525 1526 1527
}

static int
phypCreateServerSCSIAdapter(virConnectPtr conn)
{
1528
    int result = -1;
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
    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))) {
1545
        VIR_ERROR(_("Unable to get VIOS name"));
1546
        goto cleanup;
1547 1548 1549
    }

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1550
        VIR_ERROR(_("Unable to get VIOS profile name."));
1551
        goto cleanup;
1552 1553 1554
    }

    if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
1555
        VIR_ERROR(_("Unable to get free slot number"));
1556
        goto cleanup;
1557 1558 1559 1560 1561 1562 1563
    }

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1564 1565
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof --filter lpar_ids=%d,profile_names=%s"
1566 1567
                      " -F virtual_scsi_adapters|sed -e s/\\\"//g",
                      vios_id, profile);
1568
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1569 1570

    if (exit_status < 0 || ret == NULL)
1571
        goto cleanup;
1572 1573 1574 1575 1576 1577

    /* 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)
1578 1579
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d,"
1580 1581
                      "\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'",
                      vios_name, vios_id, ret, slot);
1582
    VIR_FREE(ret);
1583
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1584 1585

    if (exit_status < 0 || ret == NULL)
1586
        goto cleanup;
1587 1588 1589 1590 1591 1592

    /* 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)
1593 1594
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1595 1596
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      vios_name, slot);
1597
    VIR_FREE(ret);
1598
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1599 1600

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

1603
    result = 0;
1604

1605
cleanup:
1606 1607 1608
    VIR_FREE(profile);
    VIR_FREE(vios_name);
    VIR_FREE(ret);
1609 1610

    return result;
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
}

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)
1627
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1628 1629
                          managed_system, vios_id);

1630
    virBufferAddLit(&buf, "lsmap -all -field svsa backing -fmt , ");
1631 1632 1633 1634

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

1635
    virBufferAddLit(&buf, "|sed '/,[^.*]/d; s/,//g; q'");
1636
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1637

1638
    if (exit_status < 0)
1639 1640
        VIR_FREE(ret);
    return ret;
1641 1642 1643 1644
}


static int
1645
phypDomainAttachDevice(virDomainPtr domain, const char *xml)
1646
{
1647
    int result = -1;
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
    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;

1666
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
1667 1668
        goto cleanup;

1669
    domain_name = escape_specialcharacters(domain->name);
1670

1671
    if (domain_name == NULL) {
1672
        goto cleanup;
1673 1674
    }

1675
    if (VIR_STRDUP(def->os.type, "aix") < 0)
1676
        goto cleanup;
1677

1678 1679
    dev = virDomainDeviceDefParse(xml, def, phyp_driver->caps, NULL,
                                  VIR_DOMAIN_XML_INACTIVE);
1680
    if (!dev) {
1681
        goto cleanup;
1682 1683 1684 1685 1686
    }

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1687
        VIR_ERROR(_("Unable to get VIOS name"));
1688
        goto cleanup;
1689 1690 1691 1692 1693 1694 1695 1696
    }

    /* 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) {
1697
            VIR_ERROR(_("Unable to create new virtual adapter"));
1698
            goto cleanup;
1699 1700
        } else {
            if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
1701
                VIR_ERROR(_("Unable to create new virtual adapter"));
1702
                goto cleanup;
1703 1704 1705 1706 1707
            }
        }
    }

    if (system_type == HMC)
1708
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1709 1710
                          managed_system, vios_id);

1711
    virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
1712 1713 1714 1715
                      dev->data.disk->src, scsi_adapter);

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1716
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1717 1718

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

    if (!(profile = phypGetLparProfile(conn, domain->id))) {
1722
        VIR_ERROR(_("Unable to get VIOS profile name."));
1723
        goto cleanup;
1724 1725 1726 1727 1728 1729
    }

    /* Let's get the slot number for the adapter we just created
     * */
    virBufferAddLit(&buf, "lshwres -r virtualio --rsubtype scsi");
    if (system_type == HMC)
1730 1731
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1732 1733
                      " slot_num,backing_device|grep %s|cut -d, -f1",
                      dev->data.disk->src);
E
Eric Blake 已提交
1734
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1735
        goto cleanup;
1736 1737 1738 1739 1740 1741

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1742 1743
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1744 1745 1746
                      " -r prof --filter lpar_ids=%d,profile_names=%s"
                      " -F virtual_scsi_adapters|sed -e 's/\"//g'",
                      vios_id, profile);
1747
    VIR_FREE(ret);
1748
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1749 1750

    if (exit_status < 0 || ret == NULL)
1751
        goto cleanup;
1752 1753 1754 1755 1756 1757

    /* 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)
1758 1759
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1760 1761 1762 1763
                      " -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 已提交
1764
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1765
        goto cleanup;
1766 1767 1768 1769 1770 1771

    /* 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)
1772 1773
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1774 1775
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      domain_name, slot);
1776
    VIR_FREE(ret);
1777
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1778 1779

    if (exit_status < 0 || ret == NULL) {
1780
        VIR_ERROR(_
1781 1782
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    "Contact your support to enable this feature."));
1783
        goto cleanup;
1784 1785
    }

1786
    result = 0;
1787

1788
cleanup:
1789
    VIR_FREE(ret);
1790 1791
    virDomainDeviceDefFree(dev);
    virDomainDefFree(def);
1792 1793
    VIR_FREE(vios_name);
    VIR_FREE(scsi_adapter);
1794 1795 1796 1797
    VIR_FREE(profile);
    VIR_FREE(domain_name);

    return result;
1798 1799
}

1800
static char *
1801
phypStorageVolGetKey(virConnectPtr conn, const char *name)
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813
{
    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)
1814
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1815 1816
                          managed_system, vios_id);

1817
    virBufferAsprintf(&buf, "lslv %s -field lvid", name);
1818 1819 1820 1821

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

1822
    virBufferAddLit(&buf, "|sed -e 's/^LV IDENTIFIER://' -e 's/ //g'");
1823
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1824

1825
    if (exit_status < 0)
1826 1827
        VIR_FREE(ret);
    return ret;
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
}

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)
1844
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1845 1846
                          managed_system, vios_id);

1847
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
1848 1849 1850 1851

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

1852
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
1853
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1854

1855
    if (exit_status < 0)
1856 1857
        VIR_FREE(ret);
    return ret;
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868
}

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;
1869
    int sp_size = -1;
1870 1871 1872
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1873
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1874 1875
                          managed_system, vios_id);

1876
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
1877 1878 1879 1880

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

1881
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
E
Eric Blake 已提交
1882
    phypExecInt(session, &buf, conn, &sp_size);
1883
    return sp_size;
1884 1885
}

1886
static char *
1887
phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname,
1888
                unsigned int capacity)
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898
{
    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;
1899
    char *key = NULL;
1900 1901

    if (system_type == HMC)
1902
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1903 1904
                          managed_system, vios_id);

1905
    virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
1906 1907 1908

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1909
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1910 1911

    if (exit_status < 0) {
1912
        VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
1913
        goto cleanup;
1914 1915
    }

1916
    key = phypStorageVolGetKey(conn, lvname);
1917

1918
cleanup:
1919 1920
    VIR_FREE(ret);

1921
    return key;
1922 1923 1924
}

static virStorageVolPtr
1925
phypStorageVolLookupByName(virStoragePoolPtr pool, const char *volname)
1926
{
1927 1928
    char *key;
    virStorageVolPtr vol;
1929

1930
    key = phypStorageVolGetKey(pool->conn, volname);
1931

1932
    if (key == NULL)
1933 1934
        return NULL;

1935
    vol = virGetStorageVol(pool->conn, pool->name, volname, key, NULL, NULL);
1936 1937 1938 1939

    VIR_FREE(key);

    return vol;
1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950
}

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

    virStorageVolDefPtr voldef = NULL;
    virStoragePoolDefPtr spdef = NULL;
    virStorageVolPtr vol = NULL;
1951
    virStorageVolPtr dup_vol = NULL;
1952 1953
    char *key = NULL;

1954
    if (VIR_ALLOC(spdef) < 0)
1955 1956 1957 1958 1959 1960 1961
        return NULL;

    /* Filling spdef manually
     * */
    if (pool->name != NULL) {
        spdef->name = pool->name;
    } else {
1962
        VIR_ERROR(_("Unable to determine storage pool's name."));
1963 1964 1965 1966
        goto err;
    }

    if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
1967
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
1968 1969 1970 1971 1972
        goto err;
    }

    if ((spdef->capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
1973
        VIR_ERROR(_("Unable to determine storage pools's size."));
1974 1975 1976
        goto err;
    }

J
Ján Tomko 已提交
1977
    /* Information not available */
1978 1979 1980 1981 1982 1983
    spdef->allocation = 0;
    spdef->available = 0;

    spdef->source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
1984
    if ((spdef->source.adapter.data.name =
1985
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
1986
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
1987 1988 1989 1990
        goto err;
    }

    if ((voldef = virStorageVolDefParseString(spdef, xml)) == NULL) {
1991
        VIR_ERROR(_("Error parsing volume XML."));
1992 1993 1994 1995
        goto err;
    }

    /* checking if this name already exists on this system */
1996
    if ((dup_vol = phypStorageVolLookupByName(pool, voldef->name)) != NULL) {
1997
        VIR_ERROR(_("StoragePool name already exists."));
1998
        virObjectUnref(dup_vol);
1999 2000 2001 2002 2003 2004 2005
        goto err;
    }

    /* The key must be NULL, the Power Hypervisor creates a key
     * in the moment you create the volume.
     * */
    if (voldef->key) {
2006
        VIR_ERROR(_("Key must be empty, Power Hypervisor will create one for you."));
2007 2008 2009 2010
        goto err;
    }

    if (voldef->capacity) {
2011
        VIR_ERROR(_("Capacity cannot be empty."));
2012 2013 2014
        goto err;
    }

2015 2016 2017 2018
    key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
                          voldef->capacity);

    if (key == NULL)
2019 2020 2021 2022
        goto err;

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

2026 2027
    VIR_FREE(key);

2028 2029
    return vol;

2030
err:
2031
    VIR_FREE(key);
2032 2033
    virStorageVolDefFree(voldef);
    virStoragePoolDefFree(spdef);
2034
    virObjectUnref(vol);
2035 2036 2037 2038
    return NULL;
}

static char *
2039
phypStorageVolGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp)
2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
{
    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)
2053
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2054 2055
                          managed_system, vios_id);

2056
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
2057 2058 2059 2060

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

2061
    virBufferAddLit(&buf, "|sed 1d");
2062
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2063

2064
    if (exit_status < 0)
2065 2066
        VIR_FREE(ret);
    return ret;
2067 2068 2069
}

static virStorageVolPtr
2070
phypStorageVolLookupByPath(virConnectPtr conn, const char *volname)
2071 2072 2073 2074 2075 2076 2077 2078
{
    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;
2079
    char *ret = NULL;
2080 2081
    char *key = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2082
    virStorageVolPtr vol = NULL;
2083 2084

    if (system_type == HMC)
2085
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2086 2087
                          managed_system, vios_id);

2088
    virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
2089 2090 2091 2092

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

2093
    virBufferAddLit(&buf, "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2094
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2095

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

2099
    key = phypStorageVolGetKey(conn, volname);
2100

2101
    if (key == NULL)
2102
        goto cleanup;
2103

2104
    vol = virGetStorageVol(conn, ret, volname, key, NULL, NULL);
2105

2106
cleanup:
2107
    VIR_FREE(ret);
2108 2109 2110
    VIR_FREE(key);

    return vol;
2111 2112 2113 2114 2115 2116
}

static int
phypGetStoragePoolUUID(virConnectPtr conn, unsigned char *uuid,
                       const char *name)
{
2117
    int result = -1;
2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128
    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)
2129
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2130 2131
                          managed_system, vios_id);

2132
    virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
2133 2134 2135 2136

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

2137
    virBufferAddLit(&buf, "|sed '1,2d'");
2138
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2139 2140

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

2143
    if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
2144
        goto cleanup;
2145

2146
    result = 0;
2147

2148
cleanup:
2149
    VIR_FREE(ret);
2150 2151

    return result;
2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
}

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

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

2162
    return virGetStoragePool(conn, name, uuid, NULL, NULL);
2163 2164 2165
}

static char *
2166
phypStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
2167
{
2168 2169 2170
    virStorageVolDef voldef;
    virStoragePoolDef pool;
    virStoragePoolPtr sp;
2171
    char *xml = NULL;
2172

2173 2174 2175
    virCheckFlags(0, NULL);

    memset(&voldef, 0, sizeof(virStorageVolDef));
2176
    memset(&pool, 0, sizeof(virStoragePoolDef));
2177

2178
    sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
2179 2180

    if (!sp)
2181
        goto cleanup;
2182 2183 2184 2185

    if (sp->name != NULL) {
        pool.name = sp->name;
    } else {
2186
        VIR_ERROR(_("Unable to determine storage sp's name."));
2187
        goto cleanup;
2188 2189
    }

2190
    if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
2191
        VIR_ERROR(_("Unable to determine storage sp's uuid."));
2192
        goto cleanup;
2193 2194 2195
    }

    if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
2196
        VIR_ERROR(_("Unable to determine storage sps's size."));
2197
        goto cleanup;
2198 2199
    }

J
Ján Tomko 已提交
2200
    /* Information not available */
2201 2202 2203 2204 2205
    pool.allocation = 0;
    pool.available = 0;

    pool.source.ndevice = 1;

2206
    if ((pool.source.adapter.data.name =
2207
         phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) {
2208
        VIR_ERROR(_("Unable to determine storage sps's source adapter."));
2209
        goto cleanup;
2210 2211 2212 2213 2214
    }

    if (vol->name != NULL)
        voldef.name = vol->name;
    else {
2215
        VIR_ERROR(_("Unable to determine storage pool's name."));
2216
        goto cleanup;
2217 2218
    }

2219
    if (VIR_STRDUP(voldef.key, vol->key) < 0)
2220
        goto cleanup;
2221 2222 2223

    voldef.type = VIR_STORAGE_POOL_LOGICAL;

2224 2225 2226 2227
    xml = virStorageVolDefFormat(&pool, &voldef);

    VIR_FREE(voldef.key);

2228
cleanup:
2229
    virObjectUnref(sp);
2230
    return xml;
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241
}

/* 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 *
2242
phypStorageVolGetPath(virStorageVolPtr vol)
2243 2244 2245 2246 2247 2248 2249 2250 2251
{
    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;
2252
    char *ret = NULL;
2253 2254
    char *path = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2255
    char *pv;
2256 2257

    if (system_type == HMC)
2258
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2259 2260
                          managed_system, vios_id);

2261
    virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
2262 2263 2264 2265

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

2266
    virBufferAsprintf(&buf,
2267
                      "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2268
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2269

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

2273
    pv = phypStorageVolGetPhysicalVolumeByStoragePool(vol, ret);
2274

2275 2276
    if (!pv)
        goto cleanup;
2277

2278
    if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0)
2279
        goto cleanup;
2280

2281
cleanup:
2282
    VIR_FREE(ret);
2283
    VIR_FREE(path);
2284 2285

    return path;
2286 2287 2288 2289 2290 2291
}

static int
phypStoragePoolListVolumes(virStoragePoolPtr pool, char **const volumes,
                           int nvolumes)
{
2292
    bool success = false;
2293 2294 2295 2296 2297 2298 2299 2300 2301
    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;
2302
    size_t i;
2303 2304
    char *ret = NULL;
    char *volumes_list = NULL;
E
Eric Blake 已提交
2305
    char *char_ptr = NULL;
2306 2307 2308
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2309
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2310 2311
                          managed_system, vios_id);

2312
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2313 2314 2315 2316

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

2317
    virBufferAddLit(&buf, "|sed '1,2d'");
2318
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2319 2320 2321

    /* I need to parse the textual return in order to get the volumes */
    if (exit_status < 0 || ret == NULL)
2322
        goto cleanup;
2323 2324 2325 2326
    else {
        volumes_list = ret;

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

E
Eric Blake 已提交
2329 2330
            if (char_ptr) {
                *char_ptr = '\0';
2331
                if (VIR_STRDUP(volumes[got++], volumes_list) < 0)
2332
                    goto cleanup;
E
Eric Blake 已提交
2333 2334
                char_ptr++;
                volumes_list = char_ptr;
2335 2336 2337 2338 2339
            } else
                break;
        }
    }

2340 2341
    success = true;

2342
cleanup:
2343 2344 2345 2346 2347 2348
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(volumes[i]);

        got = -1;
    }
2349
    VIR_FREE(ret);
2350
    return got;
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
}

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;
2361
    int nvolumes = -1;
2362 2363 2364 2365 2366
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2367
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2368
                          managed_system, vios_id);
2369
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2370 2371
    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2372
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2373 2374
    if (phypExecInt(session, &buf, conn, &nvolumes) < 0)
        return -1;
2375 2376

    /* We need to remove 2 line from the header text output */
E
Eric Blake 已提交
2377
    return nvolumes - 2;
2378 2379 2380
}

static int
2381
phypStoragePoolDestroy(virStoragePoolPtr pool)
2382
{
2383
    int result = -1;
2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395
    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)
2396
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2397 2398
                          managed_system, vios_id);

2399
    virBufferAsprintf(&buf, "rmsp %s", pool->name);
2400 2401 2402

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2403
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2404 2405

    if (exit_status < 0) {
2406
        VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
2407
        goto cleanup;
2408 2409
    }

2410
    result = 0;
2411

2412
cleanup:
2413
    VIR_FREE(ret);
2414 2415

    return result;
2416 2417 2418 2419 2420
}

static int
phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
{
2421
    int result = -1;
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
    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;

2433 2434 2435 2436 2437 2438 2439
    if (source.adapter.type !=
        VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Only 'scsi_host' adapter is supported"));
        goto cleanup;
    }

2440
    if (system_type == HMC)
2441
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2442 2443
                          managed_system, vios_id);

2444
    virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
2445
                      source.adapter.data.name);
2446 2447 2448

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2449
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2450 2451

    if (exit_status < 0) {
2452
        VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
2453
        goto cleanup;
2454 2455
    }

2456
    result = 0;
2457

2458
cleanup:
2459
    VIR_FREE(ret);
2460 2461

    return result;
2462 2463 2464 2465

}

static int
2466
phypConnectNumOfStoragePools(virConnectPtr conn)
2467 2468 2469 2470 2471
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
2472
    int nsp = -1;
2473 2474 2475 2476 2477
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2478
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2479 2480
                          managed_system, vios_id);

2481
    virBufferAddLit(&buf, "lsvg");
2482 2483 2484 2485

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

2486
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2487
    phypExecInt(session, &buf, conn, &nsp);
2488
    return nsp;
2489 2490 2491
}

static int
2492
phypConnectListStoragePools(virConnectPtr conn, char **const pools, int npools)
2493
{
2494
    bool success = false;
2495 2496 2497 2498 2499 2500 2501 2502
    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;
2503
    size_t i;
2504 2505
    char *ret = NULL;
    char *storage_pools = NULL;
E
Eric Blake 已提交
2506
    char *char_ptr = NULL;
2507 2508 2509
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2510
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2511 2512
                          managed_system, vios_id);

2513
    virBufferAddLit(&buf, "lsvg");
2514 2515 2516

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2517
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2518 2519 2520

    /* I need to parse the textual return in order to get the storage pools */
    if (exit_status < 0 || ret == NULL)
2521
        goto cleanup;
2522 2523 2524 2525
    else {
        storage_pools = ret;

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

E
Eric Blake 已提交
2528 2529
            if (char_ptr) {
                *char_ptr = '\0';
2530
                if (VIR_STRDUP(pools[got++], storage_pools) < 0)
2531
                    goto cleanup;
E
Eric Blake 已提交
2532 2533
                char_ptr++;
                storage_pools = char_ptr;
2534 2535 2536 2537 2538
            } else
                break;
        }
    }

2539 2540
    success = true;

2541
cleanup:
2542 2543 2544 2545 2546 2547
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(pools[i]);

        got = -1;
    }
2548
    VIR_FREE(ret);
2549
    return got;
2550 2551 2552
}

static virStoragePoolPtr
2553 2554
phypStoragePoolLookupByUUID(virConnectPtr conn,
                            const unsigned char *uuid)
2555 2556 2557 2558 2559
{
    virStoragePoolPtr sp = NULL;
    int npools = 0;
    int gotpools = 0;
    char **pools = NULL;
2560
    size_t i = 0;
2561 2562
    unsigned char *local_uuid = NULL;

2563
    if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0)
2564 2565
        goto err;

2566
    if ((npools = phypConnectNumOfStoragePools(conn)) == -1)
2567 2568
        goto err;

2569
    if (VIR_ALLOC_N(pools, npools) < 0)
2570 2571
        goto err;

2572
    if ((gotpools = phypConnectListStoragePools(conn, pools, npools)) == -1)
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584
        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)) {
2585
            sp = virGetStoragePool(conn, pools[i], uuid, NULL, NULL);
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595
            VIR_FREE(local_uuid);
            VIR_FREE(pools);

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

2596
err:
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
    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;
2609
    virStoragePoolPtr dup_sp = NULL;
2610 2611 2612 2613 2614 2615
    virStoragePoolPtr sp = NULL;

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

    /* checking if this name already exists on this system */
2616
    if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) {
2617
        VIR_WARN("StoragePool name already exists.");
2618
        virObjectUnref(dup_sp);
2619 2620 2621 2622
        goto err;
    }

    /* checking if ID or UUID already exists on this system */
2623
    if ((dup_sp = phypStoragePoolLookupByUUID(conn, def->uuid)) != NULL) {
2624
        VIR_WARN("StoragePool uuid already exists.");
2625
        virObjectUnref(dup_sp);
2626 2627
        goto err;
    }
2628

2629
    if ((sp = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL)) == NULL)
2630 2631 2632 2633 2634 2635 2636
        goto err;

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

    return sp;

2637
err:
2638
    virStoragePoolDefFree(def);
2639
    virObjectUnref(sp);
2640 2641 2642 2643
    return NULL;
}

static char *
2644
phypStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
2645 2646 2647 2648 2649 2650 2651 2652 2653
{
    virCheckFlags(0, NULL);

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

    if (pool->name != NULL)
        def.name = pool->name;
    else {
2654
        VIR_ERROR(_("Unable to determine storage pool's name."));
2655 2656 2657
        goto err;
    }

2658
    if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2659
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2660 2661 2662 2663 2664
        goto err;
    }

    if ((def.capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2665
        VIR_ERROR(_("Unable to determine storage pools's size."));
2666 2667 2668
        goto err;
    }

J
Ján Tomko 已提交
2669
    /* Information not available */
2670 2671 2672 2673 2674 2675
    def.allocation = 0;
    def.available = 0;

    def.source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
2676
    if ((def.source.adapter.data.name =
2677
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2678
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2679 2680 2681 2682 2683
        goto err;
    }

    return virStoragePoolDefFormat(&def);

2684
err:
2685
    return NULL;
2686 2687
}

E
Eduardo Otubo 已提交
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703
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 已提交
2704
    int rv = -1;
E
Eduardo Otubo 已提交
2705 2706 2707 2708 2709

    /* Getting the remote slot number */

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

2712
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2713 2714 2715
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,slot_num|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2716
    if (phypExecInt(session, &buf, iface->conn, &slot_num) < 0)
E
Eric Blake 已提交
2717
        goto cleanup;
E
Eduardo Otubo 已提交
2718 2719 2720 2721

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

2724
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2725 2726 2727
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,lpar_id|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2728
    if (phypExecInt(session, &buf, iface->conn, &lpar_id) < 0)
E
Eric Blake 已提交
2729
        goto cleanup;
E
Eduardo Otubo 已提交
2730 2731 2732 2733

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

2736
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2737 2738
                      " -r virtualio --rsubtype eth"
                      " --id %d -o r -s %d", lpar_id, slot_num);
2739 2740
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, iface->conn, false);
E
Eduardo Otubo 已提交
2741 2742

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

E
Eric Blake 已提交
2745
    rv = 0;
E
Eduardo Otubo 已提交
2746

E
Eric Blake 已提交
2747
cleanup:
E
Eduardo Otubo 已提交
2748
    VIR_FREE(ret);
E
Eric Blake 已提交
2749
    return rv;
E
Eduardo Otubo 已提交
2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769
}

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 已提交
2770
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2771 2772

    if (!(def = virInterfaceDefParseString(xml)))
E
Eric Blake 已提交
2773
        goto cleanup;
E
Eduardo Otubo 已提交
2774 2775 2776 2777

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

2780
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2781 2782 2783
                      " -r virtualio --rsubtype slot --level slot"
                      " -Fslot_num --filter lpar_names=%s"
                      " |sort|tail -n 1", def->name);
E
Eric Blake 已提交
2784
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2785
        goto cleanup;
E
Eduardo Otubo 已提交
2786 2787 2788 2789 2790 2791 2792

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

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

2795
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2796 2797 2798
                      " -r virtualio --rsubtype eth"
                      " -p %s -o a -s %d -a port_vlan_id=1,"
                      "ieee_virtual_eth=0", def->name, slot);
2799 2800
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2801 2802

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2803
        goto cleanup;
E
Eduardo Otubo 已提交
2804 2805 2806 2807 2808 2809 2810 2811 2812

    /* 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)
2813
        virBufferAsprintf(&buf, "-m %s ", managed_system);
E
Eduardo Otubo 已提交
2814

2815
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2816 2817 2818
                      " -r virtualio --rsubtype slot --level slot"
                      " |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
                      "s/^.*drc_name=//'", def->name, slot);
2819 2820
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2821 2822 2823 2824 2825

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

2828
        virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2829 2830
                " -r virtualio --rsubtype eth"
                " -p %s -o r -s %d", def->name, slot);
2831 2832
        VIR_FREE(ret);
        ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eric Blake 已提交
2833
        goto cleanup;
E
Eduardo Otubo 已提交
2834 2835 2836 2837 2838 2839 2840
    }

    memcpy(name, ret, PHYP_IFACENAME_SIZE-1);

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

2843
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2844 2845 2846
                      "-r virtualio --rsubtype eth --level lpar "
                      " |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
                      "s/^.*mac_addr=//'", def->name, slot);
2847 2848
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2849 2850

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

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

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

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];
2877
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2878 2879 2880 2881

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

2884
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2885 2886 2887
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,slot_num |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
2888
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2889
        goto cleanup;
E
Eduardo Otubo 已提交
2890 2891 2892 2893

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

2896
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2897 2898 2899
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,lpar_id |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
2900
    if (phypExecInt(session, &buf, conn, &lpar_id) < 0)
E
Eric Blake 已提交
2901
        goto cleanup;
E
Eduardo Otubo 已提交
2902 2903 2904 2905

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

2908
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2909 2910 2911
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F lpar_id,slot_num,mac_addr|"
                      " sed -n '/%d,%d/ s/^.*,//p'", lpar_id, slot);
2912
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2913 2914

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2915
        goto cleanup;
E
Eduardo Otubo 已提交
2916 2917 2918

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

E
Eric Blake 已提交
2921
cleanup:
E
Eduardo Otubo 已提交
2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934
    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 已提交
2935
    int state = -1;
E
Eduardo Otubo 已提交
2936 2937 2938

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

2941
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2942 2943 2944
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,state |"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2945
    phypExecInt(session, &buf, iface->conn, &state);
E
Eduardo Otubo 已提交
2946 2947 2948 2949
    return state;
}

static int
2950
phypConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
E
Eduardo Otubo 已提交
2951 2952 2953 2954 2955 2956 2957 2958 2959
{
    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;
2960
    size_t i;
E
Eduardo Otubo 已提交
2961 2962
    char *ret = NULL;
    char *networks = NULL;
E
Eric Blake 已提交
2963
    char *char_ptr = NULL;
E
Eduardo Otubo 已提交
2964
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
2965
    bool success = false;
E
Eduardo Otubo 已提交
2966 2967 2968

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

E
Eric Blake 已提交
2975 2976
    /* I need to parse the textual return in order to get the network
     * interfaces */
E
Eduardo Otubo 已提交
2977
    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2978
        goto cleanup;
E
Eduardo Otubo 已提交
2979 2980 2981 2982

    networks = ret;

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

E
Eric Blake 已提交
2985 2986
        if (char_ptr) {
            *char_ptr = '\0';
2987
            if (VIR_STRDUP(names[got++], networks) < 0)
E
Eric Blake 已提交
2988
                goto cleanup;
E
Eric Blake 已提交
2989 2990
            char_ptr++;
            networks = char_ptr;
E
Eduardo Otubo 已提交
2991 2992 2993 2994 2995
        } else {
            break;
        }
    }

E
Eric Blake 已提交
2996 2997 2998 2999 3000
cleanup:
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);
    }
E
Eduardo Otubo 已提交
3001 3002 3003 3004 3005
    VIR_FREE(ret);
    return got;
}

static int
3006
phypConnectNumOfInterfaces(virConnectPtr conn)
E
Eduardo Otubo 已提交
3007 3008 3009 3010 3011 3012 3013
{
    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 已提交
3014
    int nnets = -1;
E
Eduardo Otubo 已提交
3015 3016 3017 3018
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

3021
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3022 3023
                      "-r virtualio --rsubtype eth --level lpar|"
                      "grep -v lpar_id=%d|grep -c lpar_name", vios_id);
E
Eric Blake 已提交
3024
    phypExecInt(session, &buf, conn, &nnets);
E
Eduardo Otubo 已提交
3025 3026 3027
    return nnets;
}

3028 3029
static int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
3030
{
3031
    ConnectionData *connection_data = conn->networkPrivateData;
3032
    phyp_driverPtr phyp_driver = conn->privateData;
3033 3034 3035 3036 3037 3038 3039
    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;
3040

3041 3042
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3043 3044
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F state --filter lpar_ids=%d", lpar_id);
3045
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3046

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

3050 3051 3052 3053 3054 3055
    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;
3056

3057
cleanup:
3058 3059
    VIR_FREE(ret);
    return state;
3060 3061
}

3062 3063 3064 3065
/* XXX - is this needed? */
static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED;
static int
phypDiskType(virConnectPtr conn, char *backing_device)
3066 3067
{
    phyp_driverPtr phyp_driver = conn->privateData;
3068 3069 3070 3071 3072 3073 3074 3075 3076
    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;
3077

3078 3079
    virBufferAddLit(&buf, "viosvrcmd");
    if (system_type == HMC)
3080 3081
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -p %d -c \"lssp -field name type "
E
Eric Blake 已提交
3082
                      "-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"",
3083
                      vios_id, backing_device);
3084
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3085

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

3089 3090 3091 3092
    if (STREQ(ret, "LVPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_BLOCK;
    else if (STREQ(ret, "FBPOOL"))
        disk_type = VIR_DOMAIN_DISK_TYPE_FILE;
3093

3094
cleanup:
3095 3096 3097
    VIR_FREE(ret);
    return disk_type;
}
3098

3099
static int
3100
phypConnectNumOfDefinedDomains(virConnectPtr conn)
3101
{
3102
    return phypConnectNumOfDomainsGeneric(conn, 1);
3103
}
3104

3105
static int
3106
phypConnectNumOfDomains(virConnectPtr conn)
3107
{
3108
    return phypConnectNumOfDomainsGeneric(conn, 0);
3109 3110
}

3111
static int
3112
phypConnectListDomains(virConnectPtr conn, int *ids, int nids)
3113
{
3114
    return phypConnectListDomainsGeneric(conn, ids, nids, 0);
3115
}
3116

3117
static int
3118
phypConnectListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
3119
{
3120
    bool success = false;
3121 3122 3123 3124 3125 3126 3127
    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;
3128
    size_t i;
3129 3130
    char *ret = NULL;
    char *domains = NULL;
E
Eric Blake 已提交
3131
    char *char_ptr = NULL;
3132
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3133

3134 3135
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3136
        virBufferAsprintf(&buf, " -m %s", managed_system);
3137
    virBufferAddLit(&buf, " -F name,state"
E
Eric Blake 已提交
3138
                      "|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'");
3139
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3140

3141 3142
    /* I need to parse the textual return in order to get the domains */
    if (exit_status < 0 || ret == NULL)
3143
        goto cleanup;
3144 3145
    else {
        domains = ret;
3146

3147
        while (got < nnames) {
E
Eric Blake 已提交
3148
            char_ptr = strchr(domains, '\n');
3149

E
Eric Blake 已提交
3150 3151
            if (char_ptr) {
                *char_ptr = '\0';
3152
                if (VIR_STRDUP(names[got++], domains) < 0)
3153
                    goto cleanup;
E
Eric Blake 已提交
3154 3155
                char_ptr++;
                domains = char_ptr;
3156 3157
            } else
                break;
3158
        }
3159 3160
    }

3161 3162
    success = true;

3163
cleanup:
3164 3165 3166 3167 3168 3169
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);

        got = -1;
    }
3170
    VIR_FREE(ret);
3171
    return got;
3172 3173
}

3174 3175
static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
3176
{
3177 3178 3179 3180 3181 3182 3183
    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];
3184

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

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

3192 3193 3194 3195 3196 3197
    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
3198 3199
}

3200 3201
static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
3202 3203
{
    ConnectionData *connection_data = conn->networkPrivateData;
3204
    phyp_driverPtr phyp_driver = conn->privateData;
3205
    LIBSSH2_SESSION *session = connection_data->session;
3206 3207 3208
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];
E
Eduardo Otubo 已提交
3209

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

3213
    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
3214
        goto cleanup;
3215

3216
    dom = virGetDomain(conn, lpar_name, lpar_uuid);
3217

3218 3219
    if (dom)
        dom->id = lpar_id;
3220

3221
cleanup:
3222
    VIR_FREE(lpar_name);
3223

3224
    return dom;
3225 3226
}

3227
static char *
3228
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3229
{
3230 3231
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3232
    LIBSSH2_SESSION *session = connection_data->session;
3233 3234
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;
E
Eduardo Otubo 已提交
3235

3236 3237
    /* Flags checked by virDomainDefFormat */

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

3240 3241 3242 3243 3244 3245 3246
    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) {
3247
        VIR_ERROR(_("Unable to determine domain's name."));
3248
        goto err;
E
Eduardo Otubo 已提交
3249 3250
    }

3251
    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
3252
        VIR_ERROR(_("Unable to generate random uuid."));
E
Eduardo Otubo 已提交
3253 3254
        goto err;
    }
3255

3256
    if ((def.mem.max_balloon =
3257
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
3258
        VIR_ERROR(_("Unable to determine domain's max memory."));
3259 3260
        goto err;
    }
3261

3262
    if ((def.mem.cur_balloon =
3263
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
3264
        VIR_ERROR(_("Unable to determine domain's memory."));
3265 3266
        goto err;
    }
3267

E
Eric Blake 已提交
3268
    if ((def.maxvcpus = def.vcpus =
3269
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
3270
        VIR_ERROR(_("Unable to determine domain's CPU."));
3271
        goto err;
3272
    }
3273

3274
    return virDomainDefFormat(&def, flags);
3275

3276
err:
3277 3278
    return NULL;
}
3279

3280 3281 3282
static int
phypDomainResume(virDomainPtr dom)
{
3283
    int result = -1;
3284 3285 3286 3287 3288 3289 3290 3291
    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;
3292

3293 3294
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3295 3296
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
3297
                      dom->id, dom->name);
3298
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3299

3300
    if (exit_status < 0)
3301
        goto cleanup;
3302

3303
    result = 0;
3304

3305
cleanup:
3306
    VIR_FREE(ret);
3307 3308

    return result;
3309 3310
}

3311
static int
E
Eric Blake 已提交
3312
phypDomainReboot(virDomainPtr dom, unsigned int flags)
3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324
{
    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 已提交
3325 3326
    virCheckFlags(0, -1);

3327 3328
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3329 3330
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345
                      " -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;
}

3346 3347
static int
phypDomainShutdown(virDomainPtr dom)
3348
{
3349
    int result = -1;
3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361
    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)
3362 3363
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o shutdown --id %d", dom->id);
3364
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3365 3366

    if (exit_status < 0)
3367
        goto cleanup;
3368

3369
    result = 0;
3370

3371
cleanup:
3372
    VIR_FREE(ret);
3373 3374

    return result;
3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386
}

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)
3387
        VIR_WARN("Unable to determine domain's max memory.");
3388 3389 3390

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

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

    return 0;
}

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
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;
}

3415
static int
3416 3417
phypDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
3418
{
3419
    int result = -1;
3420 3421 3422 3423 3424 3425 3426 3427 3428
    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;

3429 3430
    virCheckFlags(0, -1);

3431 3432
    virBufferAddLit(&buf, "rmsyscfg");
    if (system_type == HMC)
3433 3434
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
3435
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3436 3437

    if (exit_status < 0)
3438
        goto cleanup;
3439 3440

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
3441
        goto cleanup;
3442

3443
    dom->id = -1;
3444
    result = 0;
3445

3446
cleanup:
3447 3448
    VIR_FREE(ret);

3449
    return result;
3450
}
3451

3452 3453 3454 3455 3456 3457
static int
phypDomainDestroy(virDomainPtr dom)
{
    return phypDomainDestroyFlags(dom, 0);
}

3458 3459
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
3460
{
3461
    int result = -1;
3462 3463 3464 3465 3466 3467 3468 3469
    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;
3470

3471
    if (!def->mem.cur_balloon) {
3472 3473 3474
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <memory> on the domain XML file is missing or has "
                         "invalid value."));
3475
        goto cleanup;
3476 3477
    }

3478
    if (!def->mem.max_balloon) {
3479 3480 3481
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <currentMemory> on the domain XML file is missing or "
                         "has invalid value."));
3482
        goto cleanup;
3483 3484
    }

3485
    if (def->ndisks < 1) {
3486 3487
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain XML must contain at least one <disk> element."));
3488
        goto cleanup;
3489 3490 3491
    }

    if (!def->disks[0]->src) {
3492 3493 3494
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <src> under <disk> on the domain XML file is "
                         "missing."));
3495
        goto cleanup;
3496 3497
    }

3498 3499
    virBufferAddLit(&buf, "mksyscfg");
    if (system_type == HMC)
3500
        virBufferAsprintf(&buf, " -m %s", managed_system);
3501 3502 3503 3504
    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,
3505
                      (int) def->vcpus, def->disks[0]->src);
3506
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3507

3508
    if (exit_status < 0) {
3509
        VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
3510
        goto cleanup;
3511
    }
3512

3513
    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
3514
        VIR_ERROR(_("Unable to add LPAR to the table"));
3515
        goto cleanup;
3516
    }
3517

3518
    result = 0;
3519

3520
cleanup:
3521
    VIR_FREE(ret);
3522 3523

    return result;
3524
}
3525

3526
static virDomainPtr
3527 3528
phypDomainCreateXML(virConnectPtr conn,
                    const char *xml, unsigned int flags)
3529
{
E
Eduardo Otubo 已提交
3530
    virCheckFlags(0, NULL);
3531 3532 3533 3534 3535 3536 3537 3538

    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;
3539
    size_t i = 0;
3540 3541 3542 3543
    char *managed_system = phyp_driver->managed_system;

    virCheckFlags(0, NULL);

3544 3545 3546
    if (!(def = virDomainDefParseString(xml, phyp_driver->caps,
                                        phyp_driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_PHYP,
3547 3548 3549 3550
                                        VIR_DOMAIN_XML_SECURE)))
        goto err;

    /* checking if this name already exists on this system */
3551
    if (phypGetLparID(session, managed_system, def->name, conn) != -1) {
3552
        VIR_WARN("LPAR name already exists.");
3553 3554 3555 3556 3557 3558
        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) {
3559
            VIR_WARN("LPAR ID or UUID already exists.");
3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574
            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;

3575
err:
3576
    virDomainDefFree(def);
3577
    virObjectUnref(dom);
3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593
    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
3594 3595
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608
{
    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;

3609
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
3610
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
3611 3612 3613
        return -1;
    }

3614 3615 3616
    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        return 0;

3617
    if (nvcpus > phypDomainGetMaxVcpus(dom)) {
3618
        VIR_ERROR(_("You are trying to set a number of CPUs bigger than "
3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633
                     "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)
3634 3635
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --id %d -o %c --procunits %d 2>&1 |sed "
3636 3637
                      "-e 's/^.*\\([0-9][0-9]*.[0-9][0-9]*\\).*$/\\1/'",
                      dom->id, operation, amount);
3638
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3639 3640

    if (exit_status < 0) {
3641
        VIR_ERROR(_
3642 3643 3644 3645 3646 3647
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    " Contact your support to enable this feature."));
    }

    VIR_FREE(ret);
    return 0;
3648 3649

}
3650

3651
static int
3652
phypDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3653 3654 3655 3656
{
    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

3657
static virDrvOpenStatus
3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
phypStorageOpen(virConnectPtr conn,
                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

    return VIR_DRV_OPEN_SUCCESS;
}

static int
phypStorageClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 0;
}

static virDrvOpenStatus
phypInterfaceOpen(virConnectPtr conn,
                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                unsigned int flags)
3680
{
E
Eric Blake 已提交
3681 3682
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

3683 3684 3685
    if (conn->driver->no != VIR_DRV_PHYP)
        return VIR_DRV_OPEN_DECLINED;

3686 3687 3688 3689
    return VIR_DRV_OPEN_SUCCESS;
}

static int
3690
phypInterfaceClose(virConnectPtr conn ATTRIBUTE_UNUSED)
3691 3692 3693 3694
{
    return 0;
}

3695
static virDriver phypDriver = {
3696 3697
    .no = VIR_DRV_PHYP,
    .name = "PHYP",
3698 3699
    .connectOpen = phypConnectOpen, /* 0.7.0 */
    .connectClose = phypConnectClose, /* 0.7.0 */
3700
    .connectGetCapabilities = phypConnectGetCapabilities, /* 0.7.3 */
3701 3702 3703
    .connectListDomains = phypConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = phypConnectNumOfDomains, /* 0.7.0 */
    .domainCreateXML = phypDomainCreateXML, /* 0.7.3 */
3704 3705 3706 3707 3708 3709
    .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 */
3710
    .domainDestroyFlags = phypDomainDestroyFlags, /* 0.9.4 */
3711 3712
    .domainGetInfo = phypDomainGetInfo, /* 0.7.0 */
    .domainGetState = phypDomainGetState, /* 0.9.2 */
3713
    .domainSetVcpus = phypDomainSetVcpus, /* 0.7.3 */
3714 3715
    .domainSetVcpusFlags = phypDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = phypDomainGetVcpusFlags, /* 0.8.5 */
3716
    .domainGetMaxVcpus = phypDomainGetMaxVcpus, /* 0.7.3 */
3717
    .domainGetXMLDesc = phypDomainGetXMLDesc, /* 0.7.0 */
3718 3719 3720 3721 3722 3723 3724
    .connectListDefinedDomains = phypConnectListDefinedDomains, /* 0.7.0 */
    .connectNumOfDefinedDomains = phypConnectNumOfDefinedDomains, /* 0.7.0 */
    .domainAttachDevice = phypDomainAttachDevice, /* 0.8.2 */
    .connectIsEncrypted = phypConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = phypConnectIsSecure, /* 0.7.3 */
    .domainIsUpdated = phypDomainIsUpdated, /* 0.8.6 */
    .connectIsAlive = phypConnectIsAlive, /* 0.9.8 */
3725 3726
};

3727 3728
static virStorageDriver phypStorageDriver = {
    .name = "PHYP",
3729 3730
    .storageOpen = phypStorageOpen, /* 0.8.2 */
    .storageClose = phypStorageClose, /* 0.8.2 */
3731

3732 3733
    .connectNumOfStoragePools = phypConnectNumOfStoragePools, /* 0.8.2 */
    .connectListStoragePools = phypConnectListStoragePools, /* 0.8.2 */
3734
    .storagePoolLookupByName = phypStoragePoolLookupByName, /* 0.8.2 */
3735
    .storagePoolLookupByUUID = phypStoragePoolLookupByUUID, /* 0.8.2 */
3736
    .storagePoolCreateXML = phypStoragePoolCreateXML, /* 0.8.2 */
3737 3738
    .storagePoolDestroy = phypStoragePoolDestroy, /* 0.8.2 */
    .storagePoolGetXMLDesc = phypStoragePoolGetXMLDesc, /* 0.8.2 */
3739 3740 3741
    .storagePoolNumOfVolumes = phypStoragePoolNumOfVolumes, /* 0.8.2 */
    .storagePoolListVolumes = phypStoragePoolListVolumes, /* 0.8.2 */

3742 3743
    .storageVolLookupByName = phypStorageVolLookupByName, /* 0.8.2 */
    .storageVolLookupByPath = phypStorageVolLookupByPath, /* 0.8.2 */
3744
    .storageVolCreateXML = phypStorageVolCreateXML, /* 0.8.2 */
3745 3746
    .storageVolGetXMLDesc = phypStorageVolGetXMLDesc, /* 0.8.2 */
    .storageVolGetPath = phypStorageVolGetPath, /* 0.8.2 */
3747 3748
};

E
Eduardo Otubo 已提交
3749
static virInterfaceDriver phypInterfaceDriver = {
3750
    .name = "PHYP",
3751 3752 3753 3754
    .interfaceOpen = phypInterfaceOpen, /* 0.9.1 */
    .interfaceClose = phypInterfaceClose, /* 0.9.1 */
    .connectNumOfInterfaces = phypConnectNumOfInterfaces, /* 0.9.1 */
    .connectListInterfaces = phypConnectListInterfaces, /* 0.9.1 */
3755 3756 3757 3758
    .interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
    .interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
    .interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
    .interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
3759 3760
};

3761 3762 3763
int
phypRegister(void)
{
3764 3765 3766 3767
    if (virRegisterDriver(&phypDriver) < 0)
        return -1;
    if (virRegisterStorageDriver(&phypStorageDriver) < 0)
        return -1;
E
Eduardo Otubo 已提交
3768
    if (virRegisterInterfaceDriver(&phypInterfaceDriver) < 0)
3769
        return -1;
3770

3771 3772
    return 0;
}