phyp_driver.c 107.9 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2014 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
    if (virBufferCheckError(&tex_ret) < 0)
190 191
        return NULL;
    return virBufferContentAndReset(&tex_ret);
192

193
 err:
194 195 196 197
    (*exit_status) = SSH_CMD_ERR;
    virBufferFreeAndReset(&tex_ret);
    VIR_FREE(buffer);
    return NULL;
198 199
}

200 201 202 203 204 205 206 207 208 209 210
/* 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;

211
    if (virBufferCheckError(buf) < 0)
212 213 214 215 216 217 218 219 220 221 222 223
        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 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
/* 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;
}

247
static int
248
phypGetSystemType(virConnectPtr conn)
249 250
{
    ConnectionData *connection_data = conn->networkPrivateData;
251
    LIBSSH2_SESSION *session = connection_data->session;
252 253
    char *ret = NULL;
    int exit_status = 0;
254

255
    ret = phypExec(session, "lshmc -V", &exit_status, conn);
256

257 258
    VIR_FREE(ret);
    return exit_status;
259 260
}

261
static int
262
phypGetVIOSPartitionID(virConnectPtr conn)
263
{
264 265 266 267 268 269 270
    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;
271

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

281

282 283 284 285 286
static virCapsPtr
phypCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;
287

288 289
    if ((caps = virCapabilitiesNew(virArchFromHost(),
                                   0, 0)) == NULL)
290
        goto no_memory;
291

292 293 294 295 296 297
    /* 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);
298
        VIR_WARN
299
            ("Failed to query host NUMA topology, disabling NUMA capabilities");
300 301
    }

302 303
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "linux",
304
                                         caps->host.arch,
305 306
                                         NULL, NULL, 0, NULL)) == NULL)
        goto no_memory;
307

308 309 310
    if (virCapabilitiesAddGuestDomain(guest,
                                      "phyp", NULL, NULL, 0, NULL) == NULL)
        goto no_memory;
311

312
    return caps;
313

314
 no_memory:
315
    virObjectUnref(caps);
316 317
    return NULL;
}
318

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

339 340 341 342 343 344 345
    if (type == 0)
        state = "|grep Running";
    else if (type == 1) {
        if (system_type == HMC) {
            state = "|grep \"Not Activated\"";
        } else {
            state = "|grep \"Open Firmware\"";
346
        }
347 348
    } else
        state = " ";
349

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

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

382 383 384 385 386
    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

E
Eduardo Otubo 已提交
387 388
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
389 390
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'",
391
                      state);
392
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
393

394
    if (exit_status < 0 || ret == NULL)
395
        goto cleanup;
396 397 398 399 400 401 402 403

    /* 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;
404
            goto cleanup;
405
        }
406 407 408 409
        got++;
        line = next_line;
        while (*line == '\n')
            line++; /* skip \n */
410
    }
411

412
 cleanup:
413
    VIR_FREE(ret);
414
    return got;
415 416
}

417 418
static int
phypUUIDTable_WriteFile(virConnectPtr conn)
419
{
420 421
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
422
    size_t i = 0;
423 424 425 426 427
    int fd = -1;
    char local_file[] = "./uuid_table";

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

429
    for (i = 0; i < uuid_table->nlpars; i++) {
430 431 432
        if (safewrite(fd, &uuid_table->lpars[i]->id,
                      sizeof(uuid_table->lpars[i]->id)) !=
            sizeof(uuid_table->lpars[i]->id)) {
433
            VIR_ERROR(_("Unable to write information to local file."));
434 435 436 437 438
            goto err;
        }

        if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) !=
            VIR_UUID_BUFLEN) {
439
            VIR_ERROR(_("Unable to write information to local file."));
440
            goto err;
441 442 443
        }
    }

444 445 446 447 448
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
        goto err;
    }
449 450
    return 0;

451
 err:
452
    VIR_FORCE_CLOSE(fd);
453 454 455
    return -1;
}

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

472
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
473
                    NULLSTR(conn->uri->user)) < 0)
474
        goto cleanup;
475

476
    if (stat(local_file, &local_fileinfo) == -1) {
477
        VIR_WARN("Unable to stat local file.");
478
        goto cleanup;
479
    }
480

481
    if (!(f = fopen(local_file, "rb"))) {
482
        VIR_WARN("Unable to open local file.");
483
        goto cleanup;
484
    }
485

486 487 488 489 490
    do {
        channel =
            libssh2_scp_send(session, remote_file,
                             0x1FF & local_fileinfo.st_mode,
                             (unsigned long) local_fileinfo.st_size);
491

492 493
        if ((!channel) && (libssh2_session_last_errno(session) !=
                           LIBSSH2_ERROR_EAGAIN))
494
            goto cleanup;
495
    } while (!channel);
496

497
    do {
498
        nread = fread(buffer, 1, sizeof(buffer), f);
499
        if (nread <= 0) {
500
            if (feof(f)) {
501 502 503 504
                /* end of file */
                break;
            } else {
                VIR_ERROR(_("Failed to read from %s"), local_file);
505
                goto cleanup;
506 507 508 509
            }
        }
        ptr = buffer;
        sent = 0;
510

511 512 513 514 515 516 517 518 519 520 521 522 523
        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);
524

525
    ret = 0;
526

527
 cleanup:
528 529 530 531 532 533 534
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
535 536
    VIR_FORCE_FCLOSE(f);
    return ret;
537 538 539
}

static int
540
phypUUIDTable_RemLpar(virConnectPtr conn, int id)
541
{
E
Eduardo Otubo 已提交
542
    phyp_driverPtr phyp_driver = conn->privateData;
543
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
544
    size_t i = 0;
E
Eduardo Otubo 已提交
545

546 547 548 549 550
    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);
        }
551 552
    }

553
    if (phypUUIDTable_WriteFile(conn) == -1)
554 555
        goto err;

556
    if (phypUUIDTable_Push(conn) == -1)
557 558
        goto err;

559
    return 0;
560

561
 err:
562
    return -1;
563 564
}

565 566
static int
phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id)
567
{
E
Eduardo Otubo 已提交
568
    phyp_driverPtr phyp_driver = conn->privateData;
569
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
570
    lparPtr item = NULL;
E
Eduardo Otubo 已提交
571

572
    if (VIR_ALLOC(item) < 0)
573
        goto err;
574

575 576
    item->id = id;
    memcpy(item->uuid, uuid, VIR_UUID_BUFLEN);
577

578 579
    if (VIR_APPEND_ELEMENT_COPY(uuid_table->lpars, uuid_table->nlpars, item) < 0)
        goto err;
580

581 582
    if (phypUUIDTable_WriteFile(conn) == -1)
        goto err;
583

584
    if (phypUUIDTable_Push(conn) == -1)
585 586
        goto err;

587
    return 0;
588

589
 err:
590
    VIR_FREE(item);
591
    return -1;
592 593
}

594 595
static int
phypUUIDTable_ReadFile(virConnectPtr conn)
596
{
E
Eduardo Otubo 已提交
597
    phyp_driverPtr phyp_driver = conn->privateData;
598
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
599
    size_t i = 0;
600 601 602 603
    int fd = -1;
    char local_file[] = "./uuid_table";
    int rc = 0;
    int id;
604

605
    if ((fd = open(local_file, O_RDONLY)) == -1) {
606
        VIR_WARN("Unable to read information from local file.");
607
        goto err;
608 609
    }

610 611 612
    /* 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++) {
613

614 615
            rc = read(fd, &id, sizeof(int));
            if (rc == sizeof(int)) {
616
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
617 618 619
                    goto err;
                uuid_table->lpars[i]->id = id;
            } else {
620
                VIR_WARN
621
                    ("Unable to read from information from local file.");
622 623
                goto err;
            }
624

625 626
            rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN);
            if (rc != VIR_UUID_BUFLEN) {
627
                VIR_WARN("Unable to read information from local file.");
628 629
                goto err;
            }
630
        }
631
    }
632

633
    VIR_FORCE_CLOSE(fd);
634
    return 0;
635

636
 err:
637
    VIR_FORCE_CLOSE(fd);
638
    return -1;
639 640
}

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

659
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
660
                    NULLSTR(conn->uri->user)) < 0)
661
        goto cleanup;
662

663 664 665
    /* Trying to stat the remote file. */
    do {
        channel = libssh2_scp_recv(session, remote_file, &fileinfo);
666

667 668 669
        if (!channel) {
            if (libssh2_session_last_errno(session) !=
                LIBSSH2_ERROR_EAGAIN) {
670
                goto cleanup;
671
            } else {
672 673 674
                if (waitsocket(sock, session) < 0 && errno != EINTR) {
                    virReportSystemError(errno, "%s",
                                         _("unable to wait on libssh2 socket"));
675
                    goto cleanup;
676
                }
677 678 679
            }
        }
    } while (!channel);
680

681 682
    /* Creating a new data base based on remote file */
    if ((fd = creat(local_file, 0755)) == -1)
683
        goto cleanup;
684

685 686 687 688
    /* Request a file via SCP */
    while (got < fileinfo.st_size) {
        do {
            amount = sizeof(buffer);
689

690 691 692
            if ((fileinfo.st_size - got) < amount) {
                amount = fileinfo.st_size - got;
            }
E
Eduardo Otubo 已提交
693

694 695 696
            rc = libssh2_channel_read(channel, buffer, amount);
            if (rc > 0) {
                if (safewrite(fd, buffer, rc) != rc)
697
                    VIR_WARN
698
                        ("Unable to write information to local file.");
699

700 701 702 703
                got += rc;
                total += rc;
            }
        } while (rc > 0);
704

705 706 707 708
        if ((rc == LIBSSH2_ERROR_EAGAIN)
            && (got < fileinfo.st_size)) {
            /* this is due to blocking that would occur otherwise
             * so we loop on this condition */
709

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

726
    ret = 0;
727

728
 cleanup:
729 730 731 732 733 734 735
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
736 737
    VIR_FORCE_CLOSE(fd);
    return ret;
738 739
}

740 741
static int
phypUUIDTable_Init(virConnectPtr conn)
742
{
E
Eric Blake 已提交
743
    uuid_tablePtr uuid_table = NULL;
744 745 746 747
    phyp_driverPtr phyp_driver;
    int nids_numdomains = 0;
    int nids_listdomains = 0;
    int *ids = NULL;
748
    size_t i = 0;
E
Eric Blake 已提交
749 750
    int ret = -1;
    bool table_created = false;
E
Eduardo Otubo 已提交
751

752
    if ((nids_numdomains = phypConnectNumOfDomainsGeneric(conn, 2)) < 0)
E
Eric Blake 已提交
753
        goto cleanup;
754

755
    if (VIR_ALLOC_N(ids, nids_numdomains) < 0)
E
Eric Blake 已提交
756
        goto cleanup;
757

758
    if ((nids_listdomains =
759
         phypConnectListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0)
E
Eric Blake 已提交
760
        goto cleanup;
761

762
    /* exit early if there are no domains */
E
Eric Blake 已提交
763 764 765 766 767
    if (nids_numdomains == 0 && nids_listdomains == 0) {
        ret = 0;
        goto cleanup;
    }
    if (nids_numdomains != nids_listdomains) {
768
        VIR_ERROR(_("Unable to determine number of domains."));
E
Eric Blake 已提交
769
        goto cleanup;
770
    }
771

772 773 774
    phyp_driver = conn->privateData;
    uuid_table = phyp_driver->uuid_table;
    uuid_table->nlpars = nids_listdomains;
775

776 777 778
    /* 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 已提交
779
        table_created = true;
780 781
        if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
            for (i = 0; i < uuid_table->nlpars; i++) {
782
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
E
Eric Blake 已提交
783
                    goto cleanup;
784
                uuid_table->lpars[i]->id = ids[i];
785

786 787 788 789
                if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0)
                    VIR_WARN("Unable to generate UUID for domain %d",
                             ids[i]);
            }
790
        } else
E
Eric Blake 已提交
791
            goto cleanup;
792

793
        if (phypUUIDTable_WriteFile(conn) == -1)
E
Eric Blake 已提交
794
            goto cleanup;
795

796
        if (phypUUIDTable_Push(conn) == -1)
E
Eric Blake 已提交
797
            goto cleanup;
798 799
    } else {
        if (phypUUIDTable_ReadFile(conn) == -1)
E
Eric Blake 已提交
800
            goto cleanup;
801
    }
802

E
Eric Blake 已提交
803
    ret = 0;
804

805
 cleanup:
E
Eric Blake 已提交
806 807 808 809 810 811
    if (ret < 0 && table_created) {
        for (i = 0; i < uuid_table->nlpars; i++) {
            VIR_FREE(uuid_table->lpars[i]);
        }
        VIR_FREE(uuid_table->lpars);
    }
812
    VIR_FREE(ids);
E
Eric Blake 已提交
813
    return ret;
814 815
}

816 817
static void
phypUUIDTable_Free(uuid_tablePtr uuid_table)
818
{
819
    size_t i;
820

821 822 823 824 825 826 827 828
    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);
829 830
}

831 832 833 834 835 836 837 838
#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)
839
{
840
    size_t len = strlen(src);
841 842
    size_t i = 0;

843
    if (len == 0)
844
        return false;
845

846 847
    for (i = 0; i < len; i++) {
        switch (src[i]) {
848 849 850 851
        SPECIALCHARACTER_CASES
            return true;
        default:
            continue;
852 853 854
        }
    }

855 856
    return false;
}
857

858 859 860 861 862 863 864 865 866 867
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;

868
    if (VIR_ALLOC_N(dst, len + 1) < 0)
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
        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;
884 885
}

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

904 905
    if (userhome == NULL)
        goto err;
E
Eduardo Otubo 已提交
906

907
    if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0)
908
        goto err;
909

910
    if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0)
911 912
        goto err;

913
    if (conn->uri->user != NULL) {
914
        if (VIR_STRDUP(username, conn->uri->user) < 0)
915 916 917
            goto err;
    } else {
        if (auth == NULL || auth->cb == NULL) {
918 919
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
920 921
            goto err;
        }
922

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

925
        if (username == NULL) {
926 927
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Username request failed"));
928 929 930
            goto err;
        }
    }
931

932 933 934 935
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
936

937 938
    ret = getaddrinfo(hostname, "22", &hints, &ai);
    if (ret != 0) {
939 940
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Error while getting %s address info"), hostname);
941 942
        goto err;
    }
943

944 945 946 947 948 949 950
    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;
            }
951
            VIR_FORCE_CLOSE(sock);
952 953 954
        }
        cur = cur->ai_next;
    }
955

956 957
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to connect to %s"), hostname);
958 959
    freeaddrinfo(ai);
    goto err;
960

961
 connected:
962

963
    (*internal_socket) = sock;
964

965 966 967
    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
968 969
        goto err;

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

973
    while ((rc = libssh2_session_startup(session, sock)) ==
974
           LIBSSH2_ERROR_EAGAIN);
975
    if (rc) {
976 977
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failure establishing SSH session."));
978 979
        goto disconnect;
    }
980

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

987 988 989 990 991
    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
992
           LIBSSH2_ERROR_EAGAIN);
993

994
 keyboard_interactive:
995 996 997 998
    if (rc == LIBSSH2_ERROR_SOCKET_NONE
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
        if (auth == NULL || auth->cb == NULL) {
999 1000
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
1001 1002
            goto disconnect;
        }
1003

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

1006
        if (password == NULL) {
1007 1008
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Password request failed"));
1009 1010
            goto disconnect;
        }
1011

1012 1013 1014
        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
1015
               LIBSSH2_ERROR_EAGAIN);
1016

1017
        if (rc) {
1018 1019
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("Authentication failed"));
1020 1021 1022
            goto disconnect;
        } else
            goto exit;
1023

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

1027 1028
    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
1029 1030 1031
        goto err;
    }

1032
 disconnect:
1033 1034
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1035
 err:
1036
    VIR_FORCE_CLOSE(sock);
1037 1038 1039 1040 1041
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
1042
    return NULL;
1043

1044
 exit:
1045 1046 1047 1048 1049 1050
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return session;
1051 1052
}

1053
static virDrvOpenStatus
1054 1055
phypConnectOpen(virConnectPtr conn,
                virConnectAuthPtr auth, unsigned int flags)
1056 1057 1058 1059 1060 1061 1062 1063
{
    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 已提交
1064

E
Eric Blake 已提交
1065 1066
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1067 1068 1069 1070 1071 1072 1073
    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) {
1074 1075
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing server name in phyp:// URI"));
1076 1077 1078
        return VIR_DRV_OPEN_ERROR;
    }

1079
    if (VIR_ALLOC(phyp_driver) < 0)
1080
        goto failure;
1081

1082
    if (VIR_ALLOC(uuid_table) < 0)
1083
        goto failure;
1084

1085
    if (VIR_ALLOC(connection_data) < 0)
1086
        goto failure;
1087
    connection_data->sock = -1;
1088

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

1103
        if (contains_specialcharacters(conn->uri->path)) {
1104 1105 1106
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s",
                           _("Error parsing 'path'. Invalid characters."));
1107 1108 1109 1110 1111
            goto failure;
        }
    }

    if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
1112 1113
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Error while opening SSH session."));
1114 1115 1116 1117
        goto failure;
    }

    connection_data->session = session;
1118
    connection_data->sock = internal_socket;
1119 1120 1121 1122 1123 1124 1125 1126

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

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

    phyp_driver->uuid_table = uuid_table;
1127
    if ((phyp_driver->caps = phypCapsInit()) == NULL)
1128
        goto failure;
1129

1130
    if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)))
1131 1132
        goto failure;

1133 1134
    conn->privateData = phyp_driver;
    conn->networkPrivateData = connection_data;
1135

1136 1137
    if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
        goto failure;
1138

1139 1140
    if (phypUUIDTable_Init(conn) == -1)
        goto failure;
1141

1142 1143 1144 1145 1146 1147 1148
    if (phyp_driver->system_type == HMC) {
        if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
            goto failure;
    }

    return VIR_DRV_OPEN_SUCCESS;

1149
 failure:
1150 1151
    VIR_FREE(managed_system);

1152
    if (phyp_driver != NULL) {
1153
        virObjectUnref(phyp_driver->caps);
1154
        virObjectUnref(phyp_driver->xmlopt);
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        VIR_FREE(phyp_driver);
    }

    phypUUIDTable_Free(uuid_table);

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

1165 1166
    if (connection_data)
        VIR_FORCE_CLOSE(connection_data->sock);
1167 1168 1169
    VIR_FREE(connection_data);

    return VIR_DRV_OPEN_ERROR;
1170 1171 1172
}

static int
1173
phypConnectClose(virConnectPtr conn)
1174
{
1175 1176 1177
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
1178

1179 1180
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1181

1182
    virObjectUnref(phyp_driver->caps);
1183
    virObjectUnref(phyp_driver->xmlopt);
1184 1185 1186
    phypUUIDTable_Free(phyp_driver->uuid_table);
    VIR_FREE(phyp_driver->managed_system);
    VIR_FREE(phyp_driver);
1187 1188

    VIR_FORCE_CLOSE(connection_data->sock);
1189 1190 1191
    VIR_FREE(connection_data);
    return 0;
}
1192 1193


1194
static int
1195
phypConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1196 1197 1198 1199
{
    /* Phyp uses an SSH tunnel, so is always encrypted */
    return 1;
}
1200

1201 1202

static int
1203
phypConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1204 1205 1206
{
    /* Phyp uses an SSH tunnel, so is always secure */
    return 1;
1207 1208
}

1209 1210

static int
1211
phypConnectIsAlive(virConnectPtr conn)
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
{
    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;
}


1226
static int
1227
phypDomainIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
1228 1229 1230
{
    return 0;
}
1231 1232

/* return the lpar_id given a name and a managed system name */
1233
static int
1234 1235
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
1236
{
1237
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1238
    int system_type = phyp_driver->system_type;
1239
    int lpar_id = -1;
E
Eduardo Otubo 已提交
1240 1241
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1242
    virBufferAddLit(&buf, "lssyscfg -r lpar");
E
Eduardo Otubo 已提交
1243
    if (system_type == HMC)
1244 1245
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_names=%s -F lpar_id", name);
E
Eric Blake 已提交
1246
    phypExecInt(session, &buf, conn, &lpar_id);
1247
    return lpar_id;
1248 1249
}

1250 1251 1252 1253
/* 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)
1254 1255
{
    phyp_driverPtr phyp_driver = conn->privateData;
1256 1257 1258 1259
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1260

1261 1262
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
1263 1264
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_ids=%d -F name", lpar_id);
1265
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1266

1267
    if (exit_status < 0)
1268 1269
        VIR_FREE(ret);
    return ret;
1270 1271
}

1272 1273 1274 1275 1276 1277 1278 1279 1280

/* 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)
1281 1282
{
    phyp_driverPtr phyp_driver = conn->privateData;
1283 1284
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
1285
    size_t i = 0;
1286

1287 1288
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
1289
            memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
1290 1291 1292
            return 0;
        }
    }
1293

1294
    return -1;
1295 1296
}

1297 1298 1299 1300 1301 1302 1303 1304
/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
static unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
1305
{
1306 1307 1308 1309 1310 1311
    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;
1312

1313 1314
    if (type != 1 && type != 0)
        return 0;
1315

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

1326 1327 1328
static unsigned long
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
1329
{
1330
    ConnectionData *connection_data = conn->networkPrivateData;
1331
    LIBSSH2_SESSION *session = connection_data->session;
1332
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1333
    int system_type = phyp_driver->system_type;
1334
    int vcpus = 0;
E
Eduardo Otubo 已提交
1335
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1336

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

1347 1348 1349 1350
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
    return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
1351 1352
}

1353
static int
1354
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
1355 1356 1357
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;
1358

1359
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1360
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1361 1362 1363
        return -1;
    }

1364 1365 1366
    return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}

1367
static int
1368
phypDomainGetMaxVcpus(virDomainPtr dom)
1369 1370 1371 1372 1373
{
    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1374 1375 1376
static int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
1377
{
1378 1379
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1380
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1381
    int system_type = phyp_driver->system_type;
1382
    int remote_slot = -1;
E
Eduardo Otubo 已提交
1383 1384
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1385
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1386
    if (system_type == HMC)
1387 1388
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1389
                      "remote_slot_num --filter lpar_names=%s", lpar_name);
E
Eric Blake 已提交
1390
    phypExecInt(session, &buf, conn, &remote_slot);
1391
    return remote_slot;
1392 1393
}

1394 1395 1396 1397 1398 1399
/* 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)
1400
{
1401 1402
    ConnectionData *connection_data = conn->networkPrivateData;
    LIBSSH2_SESSION *session = connection_data->session;
1403
    phyp_driverPtr phyp_driver = conn->privateData;
1404 1405 1406 1407 1408 1409 1410
    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;
1411

1412 1413 1414 1415 1416 1417
    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        return NULL;

    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1418 1419
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1420
                      "backing_devices --filter slots=%d", remote_slot);
1421
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1422

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

1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
    /* 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
1440
            goto cleanup;
1441

1442
        if (VIR_STRDUP(backing_device, char_ptr) < 0)
1443
            goto cleanup;
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    } else {
        backing_device = ret;
        ret = NULL;
    }

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

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

1454
 cleanup:
1455
    VIR_FREE(ret);
1456

1457
    return backing_device;
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
}

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)
1474 1475
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1476 1477
                      " -r prof --filter lpar_ids=%d -F name|head -n 1",
                      lpar_id);
1478
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1479

1480
    if (exit_status < 0)
1481 1482
        VIR_FREE(ret);
    return ret;
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
}

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;
1495
    int slot = -1;
1496 1497 1498
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1499
        VIR_ERROR(_("Unable to get VIOS profile name."));
1500
        return -1;
1501 1502 1503 1504 1505
    }

    virBufferAddLit(&buf, "lssyscfg");

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

1508
    virBufferAsprintf(&buf, " -r prof --filter "
1509 1510 1511 1512 1513
                      "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 已提交
1514 1515 1516
    if (phypExecInt(session, &buf, conn, &slot) < 0)
        return -1;
    return slot + 1;
1517 1518 1519 1520 1521
}

static int
phypCreateServerSCSIAdapter(virConnectPtr conn)
{
1522
    int result = -1;
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
    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))) {
1539
        VIR_ERROR(_("Unable to get VIOS name"));
1540
        goto cleanup;
1541 1542 1543
    }

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1544
        VIR_ERROR(_("Unable to get VIOS profile name."));
1545
        goto cleanup;
1546 1547 1548
    }

    if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
1549
        VIR_ERROR(_("Unable to get free slot number"));
1550
        goto cleanup;
1551 1552 1553 1554 1555 1556 1557
    }

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

    if (exit_status < 0 || ret == NULL)
1565
        goto cleanup;
1566 1567 1568 1569 1570 1571

    /* 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)
1572 1573
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d,"
1574 1575
                      "\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'",
                      vios_name, vios_id, ret, slot);
1576
    VIR_FREE(ret);
1577
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1578 1579

    if (exit_status < 0 || ret == NULL)
1580
        goto cleanup;
1581 1582 1583 1584 1585 1586

    /* 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)
1587 1588
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1589 1590
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      vios_name, slot);
1591
    VIR_FREE(ret);
1592
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1593 1594

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

1597
    result = 0;
1598

1599
 cleanup:
1600 1601 1602
    VIR_FREE(profile);
    VIR_FREE(vios_name);
    VIR_FREE(ret);
1603 1604

    return result;
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
}

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

1624
    virBufferAddLit(&buf, "lsmap -all -field svsa backing -fmt , ");
1625 1626 1627 1628

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

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

1632
    if (exit_status < 0)
1633 1634
        VIR_FREE(ret);
    return ret;
1635 1636 1637 1638
}


static int
1639
phypDomainAttachDevice(virDomainPtr domain, const char *xml)
1640
{
1641
    int result = -1;
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
    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;

1660
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
1661 1662
        goto cleanup;

1663
    domain_name = escape_specialcharacters(domain->name);
1664

1665
    if (domain_name == NULL) {
1666
        goto cleanup;
1667 1668
    }

1669
    if (VIR_STRDUP(def->os.type, "aix") < 0)
1670
        goto cleanup;
1671

1672 1673
    dev = virDomainDeviceDefParse(xml, def, phyp_driver->caps, NULL,
                                  VIR_DOMAIN_XML_INACTIVE);
1674
    if (!dev) {
1675
        goto cleanup;
1676 1677 1678 1679 1680
    }

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1681
        VIR_ERROR(_("Unable to get VIOS name"));
1682
        goto cleanup;
1683 1684 1685 1686 1687 1688 1689 1690
    }

    /* 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) {
1691
            VIR_ERROR(_("Unable to create new virtual adapter"));
1692
            goto cleanup;
1693 1694
        } else {
            if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
1695
                VIR_ERROR(_("Unable to create new virtual adapter"));
1696
                goto cleanup;
1697 1698 1699 1700 1701
            }
        }
    }

    if (system_type == HMC)
1702
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1703 1704
                          managed_system, vios_id);

1705
    virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
1706
                      virDomainDiskGetSource(dev->data.disk), scsi_adapter);
1707 1708 1709

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1710
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1711 1712

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

    if (!(profile = phypGetLparProfile(conn, domain->id))) {
1716
        VIR_ERROR(_("Unable to get VIOS profile name."));
1717
        goto cleanup;
1718 1719 1720 1721 1722 1723
    }

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

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

    if (exit_status < 0 || ret == NULL)
1745
        goto cleanup;
1746 1747 1748 1749 1750 1751

    /* 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)
1752 1753
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1754 1755 1756 1757
                      " -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 已提交
1758
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1759
        goto cleanup;
1760 1761 1762 1763 1764 1765

    /* 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)
1766 1767
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1768 1769
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      domain_name, slot);
1770
    VIR_FREE(ret);
1771
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1772 1773

    if (exit_status < 0 || ret == NULL) {
1774
        VIR_ERROR(_
1775 1776
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    "Contact your support to enable this feature."));
1777
        goto cleanup;
1778 1779
    }

1780
    result = 0;
1781

1782
 cleanup:
1783
    VIR_FREE(ret);
1784 1785
    virDomainDeviceDefFree(dev);
    virDomainDefFree(def);
1786 1787
    VIR_FREE(vios_name);
    VIR_FREE(scsi_adapter);
1788 1789 1790 1791
    VIR_FREE(profile);
    VIR_FREE(domain_name);

    return result;
1792 1793
}

1794
static char *
1795
phypStorageVolGetKey(virConnectPtr conn, const char *name)
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
{
    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)
1808
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1809 1810
                          managed_system, vios_id);

1811
    virBufferAsprintf(&buf, "lslv %s -field lvid", name);
1812 1813 1814 1815

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

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

1819
    if (exit_status < 0)
1820 1821
        VIR_FREE(ret);
    return ret;
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837
}

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

1841
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
1842 1843 1844 1845

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

1846
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
1847
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1848

1849
    if (exit_status < 0)
1850 1851
        VIR_FREE(ret);
    return ret;
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
}

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;
1863
    int sp_size = -1;
1864 1865 1866
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1867
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1868 1869
                          managed_system, vios_id);

1870
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
1871 1872 1873 1874

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

1875
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
E
Eric Blake 已提交
1876
    phypExecInt(session, &buf, conn, &sp_size);
1877
    return sp_size;
1878 1879
}

1880
static char *
1881
phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname,
1882
                unsigned int capacity)
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
{
    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;
1893
    char *key = NULL;
1894 1895

    if (system_type == HMC)
1896
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1897 1898
                          managed_system, vios_id);

1899
    virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
1900 1901 1902

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1903
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1904 1905

    if (exit_status < 0) {
1906
        VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
1907
        goto cleanup;
1908 1909
    }

1910
    key = phypStorageVolGetKey(conn, lvname);
1911

1912
 cleanup:
1913 1914
    VIR_FREE(ret);

1915
    return key;
1916 1917 1918
}

static virStorageVolPtr
1919
phypStorageVolLookupByName(virStoragePoolPtr pool, const char *volname)
1920
{
1921 1922
    char *key;
    virStorageVolPtr vol;
1923

1924
    key = phypStorageVolGetKey(pool->conn, volname);
1925

1926
    if (key == NULL)
1927 1928
        return NULL;

1929
    vol = virGetStorageVol(pool->conn, pool->name, volname, key, NULL, NULL);
1930 1931 1932 1933

    VIR_FREE(key);

    return vol;
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
}

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

    virStorageVolDefPtr voldef = NULL;
    virStoragePoolDefPtr spdef = NULL;
    virStorageVolPtr vol = NULL;
1945
    virStorageVolPtr dup_vol = NULL;
1946 1947
    char *key = NULL;

1948
    if (VIR_ALLOC(spdef) < 0)
1949 1950 1951 1952 1953 1954 1955
        return NULL;

    /* Filling spdef manually
     * */
    if (pool->name != NULL) {
        spdef->name = pool->name;
    } else {
1956
        VIR_ERROR(_("Unable to determine storage pool's name."));
1957 1958 1959 1960
        goto err;
    }

    if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
1961
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
1962 1963 1964 1965 1966
        goto err;
    }

    if ((spdef->capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
1967
        VIR_ERROR(_("Unable to determine storage pools's size."));
1968 1969 1970
        goto err;
    }

J
Ján Tomko 已提交
1971
    /* Information not available */
1972 1973 1974 1975 1976 1977
    spdef->allocation = 0;
    spdef->available = 0;

    spdef->source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
1978
    if ((spdef->source.adapter.data.name =
1979
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
1980
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
1981 1982 1983 1984
        goto err;
    }

    if ((voldef = virStorageVolDefParseString(spdef, xml)) == NULL) {
1985
        VIR_ERROR(_("Error parsing volume XML."));
1986 1987 1988 1989
        goto err;
    }

    /* checking if this name already exists on this system */
1990
    if ((dup_vol = phypStorageVolLookupByName(pool, voldef->name)) != NULL) {
1991
        VIR_ERROR(_("StoragePool name already exists."));
1992
        virObjectUnref(dup_vol);
1993 1994 1995 1996 1997 1998 1999
        goto err;
    }

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

2004
    if (!voldef->target.capacity) {
2005
        VIR_ERROR(_("Capacity cannot be empty."));
2006 2007 2008
        goto err;
    }

2009
    key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
2010
                          voldef->target.capacity);
2011 2012

    if (key == NULL)
2013 2014 2015 2016
        goto err;

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

2020 2021
    VIR_FREE(key);

2022 2023
    return vol;

2024
 err:
2025
    VIR_FREE(key);
2026 2027
    virStorageVolDefFree(voldef);
    virStoragePoolDefFree(spdef);
2028
    virObjectUnref(vol);
2029 2030 2031 2032
    return NULL;
}

static char *
2033
phypStorageVolGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp)
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
{
    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)
2047
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2048 2049
                          managed_system, vios_id);

2050
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
2051 2052 2053 2054

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

2055
    virBufferAddLit(&buf, "|sed 1d");
2056
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2057

2058
    if (exit_status < 0)
2059 2060
        VIR_FREE(ret);
    return ret;
2061 2062 2063
}

static virStorageVolPtr
2064
phypStorageVolLookupByPath(virConnectPtr conn, const char *volname)
2065 2066 2067 2068 2069 2070 2071 2072
{
    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;
2073
    char *ret = NULL;
2074 2075
    char *key = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2076
    virStorageVolPtr vol = NULL;
2077 2078

    if (system_type == HMC)
2079
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2080 2081
                          managed_system, vios_id);

2082
    virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
2083 2084 2085 2086

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

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

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

2093
    key = phypStorageVolGetKey(conn, volname);
2094

2095
    if (key == NULL)
2096
        goto cleanup;
2097

2098
    vol = virGetStorageVol(conn, ret, volname, key, NULL, NULL);
2099

2100
 cleanup:
2101
    VIR_FREE(ret);
2102 2103 2104
    VIR_FREE(key);

    return vol;
2105 2106 2107 2108 2109 2110
}

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

2126
    virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
2127 2128 2129 2130

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

2131
    virBufferAddLit(&buf, "|sed '1,2d'");
2132
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2133 2134

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

2137
    if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
2138
        goto cleanup;
2139

2140
    result = 0;
2141

2142
 cleanup:
2143
    VIR_FREE(ret);
2144 2145

    return result;
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
}

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

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

2156
    return virGetStoragePool(conn, name, uuid, NULL, NULL);
2157 2158 2159
}

static char *
2160
phypStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
2161
{
2162 2163 2164
    virStorageVolDef voldef;
    virStoragePoolDef pool;
    virStoragePoolPtr sp;
2165
    char *xml = NULL;
2166

2167 2168 2169
    virCheckFlags(0, NULL);

    memset(&voldef, 0, sizeof(virStorageVolDef));
2170
    memset(&pool, 0, sizeof(virStoragePoolDef));
2171

2172
    sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
2173 2174

    if (!sp)
2175
        goto cleanup;
2176 2177 2178 2179

    if (sp->name != NULL) {
        pool.name = sp->name;
    } else {
2180
        VIR_ERROR(_("Unable to determine storage sp's name."));
2181
        goto cleanup;
2182 2183
    }

2184
    if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
2185
        VIR_ERROR(_("Unable to determine storage sp's uuid."));
2186
        goto cleanup;
2187 2188 2189
    }

    if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
2190
        VIR_ERROR(_("Unable to determine storage sps's size."));
2191
        goto cleanup;
2192 2193
    }

J
Ján Tomko 已提交
2194
    /* Information not available */
2195 2196 2197 2198 2199
    pool.allocation = 0;
    pool.available = 0;

    pool.source.ndevice = 1;

2200
    if ((pool.source.adapter.data.name =
2201
         phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) {
2202
        VIR_ERROR(_("Unable to determine storage sps's source adapter."));
2203
        goto cleanup;
2204 2205 2206 2207 2208
    }

    if (vol->name != NULL)
        voldef.name = vol->name;
    else {
2209
        VIR_ERROR(_("Unable to determine storage pool's name."));
2210
        goto cleanup;
2211 2212
    }

2213
    if (VIR_STRDUP(voldef.key, vol->key) < 0)
2214
        goto cleanup;
2215 2216 2217

    voldef.type = VIR_STORAGE_POOL_LOGICAL;

2218 2219 2220 2221
    xml = virStorageVolDefFormat(&pool, &voldef);

    VIR_FREE(voldef.key);

2222
 cleanup:
2223
    virObjectUnref(sp);
2224
    return xml;
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
}

/* 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 *
2236
phypStorageVolGetPath(virStorageVolPtr vol)
2237 2238 2239 2240 2241 2242 2243 2244 2245
{
    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;
2246
    char *ret = NULL;
2247 2248
    char *path = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2249
    char *pv;
2250 2251

    if (system_type == HMC)
2252
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2253 2254
                          managed_system, vios_id);

2255
    virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
2256 2257 2258 2259

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

2260
    virBufferAsprintf(&buf,
2261
                      "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2262
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2263

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

2267
    pv = phypStorageVolGetPhysicalVolumeByStoragePool(vol, ret);
2268

2269 2270
    if (!pv)
        goto cleanup;
2271

2272
    if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0)
2273
        goto cleanup;
2274

2275
 cleanup:
2276
    VIR_FREE(ret);
2277
    VIR_FREE(path);
2278 2279

    return path;
2280 2281 2282 2283 2284 2285
}

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

    if (system_type == HMC)
2303
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2304 2305
                          managed_system, vios_id);

2306
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2307 2308 2309 2310

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

2311
    virBufferAddLit(&buf, "|sed '1,2d'");
2312
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2313 2314 2315

    /* I need to parse the textual return in order to get the volumes */
    if (exit_status < 0 || ret == NULL)
2316
        goto cleanup;
2317 2318 2319 2320
    else {
        volumes_list = ret;

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

E
Eric Blake 已提交
2323 2324
            if (char_ptr) {
                *char_ptr = '\0';
2325
                if (VIR_STRDUP(volumes[got++], volumes_list) < 0)
2326
                    goto cleanup;
E
Eric Blake 已提交
2327 2328
                char_ptr++;
                volumes_list = char_ptr;
2329 2330 2331 2332 2333
            } else
                break;
        }
    }

2334 2335
    success = true;

2336
 cleanup:
2337 2338 2339 2340 2341 2342
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(volumes[i]);

        got = -1;
    }
2343
    VIR_FREE(ret);
2344
    return got;
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354
}

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;
2355
    int nvolumes = -1;
2356 2357 2358 2359 2360
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

    /* We need to remove 2 line from the header text output */
E
Eric Blake 已提交
2371
    return nvolumes - 2;
2372 2373 2374
}

static int
2375
phypStoragePoolDestroy(virStoragePoolPtr pool)
2376
{
2377
    int result = -1;
2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389
    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)
2390
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2391 2392
                          managed_system, vios_id);

2393
    virBufferAsprintf(&buf, "rmsp %s", pool->name);
2394 2395 2396

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2397
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2398 2399

    if (exit_status < 0) {
2400
        VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
2401
        goto cleanup;
2402 2403
    }

2404
    result = 0;
2405

2406
 cleanup:
2407
    VIR_FREE(ret);
2408 2409

    return result;
2410 2411 2412 2413 2414
}

static int
phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
{
2415
    int result = -1;
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426
    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;

2427 2428 2429 2430 2431 2432 2433
    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;
    }

2434
    if (system_type == HMC)
2435
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2436 2437
                          managed_system, vios_id);

2438
    virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
2439
                      source.adapter.data.name);
2440 2441 2442

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2443
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2444 2445

    if (exit_status < 0) {
2446
        VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
2447
        goto cleanup;
2448 2449
    }

2450
    result = 0;
2451

2452
 cleanup:
2453
    VIR_FREE(ret);
2454 2455

    return result;
2456 2457 2458 2459

}

static int
2460
phypConnectNumOfStoragePools(virConnectPtr conn)
2461 2462 2463 2464 2465
{
    ConnectionData *connection_data = conn->networkPrivateData;
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = connection_data->session;
    int system_type = phyp_driver->system_type;
2466
    int nsp = -1;
2467 2468 2469 2470 2471
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2472
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2473 2474
                          managed_system, vios_id);

2475
    virBufferAddLit(&buf, "lsvg");
2476 2477 2478 2479

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

2480
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2481
    phypExecInt(session, &buf, conn, &nsp);
2482
    return nsp;
2483 2484 2485
}

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

    if (system_type == HMC)
2504
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2505 2506
                          managed_system, vios_id);

2507
    virBufferAddLit(&buf, "lsvg");
2508 2509 2510

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2511
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2512 2513 2514

    /* I need to parse the textual return in order to get the storage pools */
    if (exit_status < 0 || ret == NULL)
2515
        goto cleanup;
2516 2517 2518 2519
    else {
        storage_pools = ret;

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

E
Eric Blake 已提交
2522 2523
            if (char_ptr) {
                *char_ptr = '\0';
2524
                if (VIR_STRDUP(pools[got++], storage_pools) < 0)
2525
                    goto cleanup;
E
Eric Blake 已提交
2526 2527
                char_ptr++;
                storage_pools = char_ptr;
2528 2529 2530 2531 2532
            } else
                break;
        }
    }

2533 2534
    success = true;

2535
 cleanup:
2536 2537 2538 2539 2540 2541
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(pools[i]);

        got = -1;
    }
2542
    VIR_FREE(ret);
2543
    return got;
2544 2545 2546
}

static virStoragePoolPtr
2547 2548
phypStoragePoolLookupByUUID(virConnectPtr conn,
                            const unsigned char *uuid)
2549 2550 2551 2552 2553
{
    virStoragePoolPtr sp = NULL;
    int npools = 0;
    int gotpools = 0;
    char **pools = NULL;
2554
    size_t i = 0;
2555 2556
    unsigned char *local_uuid = NULL;

2557
    if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0)
2558 2559
        goto err;

2560
    if ((npools = phypConnectNumOfStoragePools(conn)) == -1)
2561 2562
        goto err;

2563
    if (VIR_ALLOC_N(pools, npools) < 0)
2564 2565
        goto err;

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

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

2590
 err:
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
    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;
2603
    virStoragePoolPtr dup_sp = NULL;
2604 2605 2606 2607 2608 2609
    virStoragePoolPtr sp = NULL;

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

    /* checking if this name already exists on this system */
2610
    if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) {
2611
        VIR_WARN("StoragePool name already exists.");
2612
        virObjectUnref(dup_sp);
2613 2614 2615 2616
        goto err;
    }

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

2623
    if ((sp = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL)) == NULL)
2624 2625 2626 2627 2628 2629 2630
        goto err;

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

    return sp;

2631
 err:
2632
    virStoragePoolDefFree(def);
2633
    virObjectUnref(sp);
2634 2635 2636 2637
    return NULL;
}

static char *
2638
phypStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
2639 2640 2641 2642 2643 2644 2645 2646 2647
{
    virCheckFlags(0, NULL);

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

    if (pool->name != NULL)
        def.name = pool->name;
    else {
2648
        VIR_ERROR(_("Unable to determine storage pool's name."));
2649 2650 2651
        goto err;
    }

2652
    if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2653
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2654 2655 2656 2657 2658
        goto err;
    }

    if ((def.capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2659
        VIR_ERROR(_("Unable to determine storage pools's size."));
2660 2661 2662
        goto err;
    }

J
Ján Tomko 已提交
2663
    /* Information not available */
2664 2665 2666 2667 2668 2669
    def.allocation = 0;
    def.available = 0;

    def.source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
2670
    if ((def.source.adapter.data.name =
2671
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2672
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2673 2674 2675 2676 2677
        goto err;
    }

    return virStoragePoolDefFormat(&def);

2678
 err:
2679
    return NULL;
2680 2681
}

E
Eduardo Otubo 已提交
2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697
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 已提交
2698
    int rv = -1;
E
Eduardo Otubo 已提交
2699 2700 2701 2702 2703

    /* Getting the remote slot number */

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

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

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

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

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

2730
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2731 2732
                      " -r virtualio --rsubtype eth"
                      " --id %d -o r -s %d", lpar_id, slot_num);
2733 2734
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, iface->conn, false);
E
Eduardo Otubo 已提交
2735 2736

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

E
Eric Blake 已提交
2739
    rv = 0;
E
Eduardo Otubo 已提交
2740

2741
 cleanup:
E
Eduardo Otubo 已提交
2742
    VIR_FREE(ret);
E
Eric Blake 已提交
2743
    return rv;
E
Eduardo Otubo 已提交
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763
}

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 已提交
2764
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2765 2766

    if (!(def = virInterfaceDefParseString(xml)))
E
Eric Blake 已提交
2767
        goto cleanup;
E
Eduardo Otubo 已提交
2768 2769 2770 2771

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

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

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

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

2789
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2790 2791 2792
                      " -r virtualio --rsubtype eth"
                      " -p %s -o a -s %d -a port_vlan_id=1,"
                      "ieee_virtual_eth=0", def->name, slot);
2793 2794
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2795 2796

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2797
        goto cleanup;
E
Eduardo Otubo 已提交
2798 2799 2800 2801 2802 2803 2804 2805 2806

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

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

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

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

    memcpy(name, ret, PHYP_IFACENAME_SIZE-1);

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

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

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2845
        goto cleanup;
E
Eduardo Otubo 已提交
2846 2847 2848

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2851
 cleanup:
E
Eduardo Otubo 已提交
2852 2853
    VIR_FREE(ret);
    virInterfaceDefFree(def);
E
Eric Blake 已提交
2854
    return result;
E
Eduardo Otubo 已提交
2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
}

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];
2871
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2872 2873 2874 2875

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

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

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

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

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

2902
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2903 2904 2905
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F lpar_id,slot_num,mac_addr|"
                      " sed -n '/%d,%d/ s/^.*,//p'", lpar_id, slot);
2906
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2907 2908

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2909
        goto cleanup;
E
Eduardo Otubo 已提交
2910 2911 2912

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2915
 cleanup:
E
Eduardo Otubo 已提交
2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928
    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 已提交
2929
    int state = -1;
E
Eduardo Otubo 已提交
2930 2931 2932

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

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

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

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

E
Eric Blake 已提交
2969 2970
    /* I need to parse the textual return in order to get the network
     * interfaces */
E
Eduardo Otubo 已提交
2971
    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2972
        goto cleanup;
E
Eduardo Otubo 已提交
2973 2974 2975 2976

    networks = ret;

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

E
Eric Blake 已提交
2979 2980
        if (char_ptr) {
            *char_ptr = '\0';
2981
            if (VIR_STRDUP(names[got++], networks) < 0)
E
Eric Blake 已提交
2982
                goto cleanup;
E
Eric Blake 已提交
2983 2984
            char_ptr++;
            networks = char_ptr;
E
Eduardo Otubo 已提交
2985 2986 2987 2988 2989
        } else {
            break;
        }
    }

2990
 cleanup:
E
Eric Blake 已提交
2991 2992 2993 2994
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);
    }
E
Eduardo Otubo 已提交
2995 2996 2997 2998 2999
    VIR_FREE(ret);
    return got;
}

static int
3000
phypConnectNumOfInterfaces(virConnectPtr conn)
E
Eduardo Otubo 已提交
3001 3002 3003 3004 3005 3006 3007
{
    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 已提交
3008
    int nnets = -1;
E
Eduardo Otubo 已提交
3009 3010 3011 3012
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

3015
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3016 3017
                      "-r virtualio --rsubtype eth --level lpar|"
                      "grep -v lpar_id=%d|grep -c lpar_name", vios_id);
E
Eric Blake 已提交
3018
    phypExecInt(session, &buf, conn, &nnets);
E
Eduardo Otubo 已提交
3019 3020 3021
    return nnets;
}

3022 3023
static int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
3024
{
3025
    ConnectionData *connection_data = conn->networkPrivateData;
3026
    phyp_driverPtr phyp_driver = conn->privateData;
3027 3028 3029 3030 3031 3032 3033
    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;
3034

3035 3036
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3037 3038
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F state --filter lpar_ids=%d", lpar_id);
3039
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3040

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

3044 3045 3046 3047 3048 3049
    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;
3050

3051
 cleanup:
3052 3053
    VIR_FREE(ret);
    return state;
3054 3055
}

3056 3057 3058 3059
/* XXX - is this needed? */
static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED;
static int
phypDiskType(virConnectPtr conn, char *backing_device)
3060 3061
{
    phyp_driverPtr phyp_driver = conn->privateData;
3062 3063 3064 3065 3066 3067 3068 3069 3070
    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;
3071

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

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

3083
    if (STREQ(ret, "LVPOOL"))
E
Eric Blake 已提交
3084
        disk_type = VIR_STORAGE_TYPE_BLOCK;
3085
    else if (STREQ(ret, "FBPOOL"))
E
Eric Blake 已提交
3086
        disk_type = VIR_STORAGE_TYPE_FILE;
3087

3088
 cleanup:
3089 3090 3091
    VIR_FREE(ret);
    return disk_type;
}
3092

3093
static int
3094
phypConnectNumOfDefinedDomains(virConnectPtr conn)
3095
{
3096
    return phypConnectNumOfDomainsGeneric(conn, 1);
3097
}
3098

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

3105
static int
3106
phypConnectListDomains(virConnectPtr conn, int *ids, int nids)
3107
{
3108
    return phypConnectListDomainsGeneric(conn, ids, nids, 0);
3109
}
3110

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

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

3135 3136
    /* I need to parse the textual return in order to get the domains */
    if (exit_status < 0 || ret == NULL)
3137
        goto cleanup;
3138 3139
    else {
        domains = ret;
3140

3141
        while (got < nnames) {
E
Eric Blake 已提交
3142
            char_ptr = strchr(domains, '\n');
3143

E
Eric Blake 已提交
3144 3145
            if (char_ptr) {
                *char_ptr = '\0';
3146
                if (VIR_STRDUP(names[got++], domains) < 0)
3147
                    goto cleanup;
E
Eric Blake 已提交
3148 3149
                char_ptr++;
                domains = char_ptr;
3150 3151
            } else
                break;
3152
        }
3153 3154
    }

3155 3156
    success = true;

3157
 cleanup:
3158 3159 3160 3161 3162 3163
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);

        got = -1;
    }
3164
    VIR_FREE(ret);
3165
    return got;
3166 3167
}

3168 3169
static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
3170
{
3171 3172 3173 3174 3175 3176 3177
    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];
3178

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

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

3186 3187 3188 3189 3190 3191
    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
3192 3193
}

3194 3195
static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
3196 3197
{
    ConnectionData *connection_data = conn->networkPrivateData;
3198
    phyp_driverPtr phyp_driver = conn->privateData;
3199
    LIBSSH2_SESSION *session = connection_data->session;
3200 3201 3202
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];
E
Eduardo Otubo 已提交
3203

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

3207
    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
3208
        goto cleanup;
3209

3210
    dom = virGetDomain(conn, lpar_name, lpar_uuid);
3211

3212 3213
    if (dom)
        dom->id = lpar_id;
3214

3215
 cleanup:
3216
    VIR_FREE(lpar_name);
3217

3218
    return dom;
3219 3220
}

3221
static char *
3222
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3223
{
3224 3225
    ConnectionData *connection_data = dom->conn->networkPrivateData;
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3226
    LIBSSH2_SESSION *session = connection_data->session;
3227 3228
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;
E
Eduardo Otubo 已提交
3229

3230 3231
    /* Flags checked by virDomainDefFormat */

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

3234 3235 3236 3237 3238 3239 3240
    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) {
3241
        VIR_ERROR(_("Unable to determine domain's name."));
3242
        goto err;
E
Eduardo Otubo 已提交
3243 3244
    }

3245
    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
3246
        VIR_ERROR(_("Unable to generate random uuid."));
E
Eduardo Otubo 已提交
3247 3248
        goto err;
    }
3249

3250
    if ((def.mem.max_balloon =
3251
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
3252
        VIR_ERROR(_("Unable to determine domain's max memory."));
3253 3254
        goto err;
    }
3255

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

E
Eric Blake 已提交
3262
    if ((def.maxvcpus = def.vcpus =
3263
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
3264
        VIR_ERROR(_("Unable to determine domain's CPU."));
3265
        goto err;
3266
    }
3267

3268
    return virDomainDefFormat(&def, flags);
3269

3270
 err:
3271 3272
    return NULL;
}
3273

3274 3275 3276
static int
phypDomainResume(virDomainPtr dom)
{
3277
    int result = -1;
3278 3279 3280 3281 3282 3283 3284 3285
    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;
3286

3287 3288
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3289 3290
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
3291
                      dom->id, dom->name);
3292
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3293

3294
    if (exit_status < 0)
3295
        goto cleanup;
3296

3297
    result = 0;
3298

3299
 cleanup:
3300
    VIR_FREE(ret);
3301 3302

    return result;
3303 3304
}

3305
static int
E
Eric Blake 已提交
3306
phypDomainReboot(virDomainPtr dom, unsigned int flags)
3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318
{
    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 已提交
3319 3320
    virCheckFlags(0, -1);

3321 3322
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3323 3324
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
3325 3326 3327 3328 3329 3330 3331 3332 3333
                      " -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;

3334
 cleanup:
3335 3336 3337 3338 3339
    VIR_FREE(ret);

    return result;
}

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

    if (exit_status < 0)
3361
        goto cleanup;
3362

3363
    result = 0;
3364

3365
 cleanup:
3366
    VIR_FREE(ret);
3367 3368

    return result;
3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380
}

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)
3381
        VIR_WARN("Unable to determine domain's max memory.");
3382 3383 3384

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

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

    return 0;
}

3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408
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;
}

3409
static int
3410 3411
phypDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
3412
{
3413
    int result = -1;
3414 3415 3416 3417 3418 3419 3420 3421 3422
    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;

3423 3424
    virCheckFlags(0, -1);

3425 3426
    virBufferAddLit(&buf, "rmsyscfg");
    if (system_type == HMC)
3427 3428
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
3429
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3430 3431

    if (exit_status < 0)
3432
        goto cleanup;
3433 3434

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
3435
        goto cleanup;
3436

3437
    dom->id = -1;
3438
    result = 0;
3439

3440
 cleanup:
3441 3442
    VIR_FREE(ret);

3443
    return result;
3444
}
3445

3446 3447 3448 3449 3450 3451
static int
phypDomainDestroy(virDomainPtr dom)
{
    return phypDomainDestroyFlags(dom, 0);
}

3452 3453
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
3454
{
3455
    int result = -1;
3456 3457 3458 3459 3460 3461 3462 3463
    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;
3464

3465
    if (!def->mem.cur_balloon) {
3466 3467 3468
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <memory> on the domain XML file is missing or has "
                         "invalid value."));
3469
        goto cleanup;
3470 3471
    }

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

3479
    if (def->ndisks < 1) {
3480 3481
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain XML must contain at least one <disk> element."));
3482
        goto cleanup;
3483 3484
    }

3485
    if (!virDomainDiskGetSource(def->disks[0])) {
3486 3487 3488
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <src> under <disk> on the domain XML file is "
                         "missing."));
3489
        goto cleanup;
3490 3491
    }

3492 3493
    virBufferAddLit(&buf, "mksyscfg");
    if (system_type == HMC)
3494
        virBufferAsprintf(&buf, " -m %s", managed_system);
3495 3496 3497 3498
    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,
3499
                      (int) def->vcpus, virDomainDiskGetSource(def->disks[0]));
3500
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3501

3502
    if (exit_status < 0) {
3503
        VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
3504
        goto cleanup;
3505
    }
3506

3507
    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
3508
        VIR_ERROR(_("Unable to add LPAR to the table"));
3509
        goto cleanup;
3510
    }
3511

3512
    result = 0;
3513

3514
 cleanup:
3515
    VIR_FREE(ret);
3516 3517

    return result;
3518
}
3519

3520
static virDomainPtr
3521 3522
phypDomainCreateXML(virConnectPtr conn,
                    const char *xml, unsigned int flags)
3523
{
E
Eduardo Otubo 已提交
3524
    virCheckFlags(0, NULL);
3525 3526 3527 3528 3529 3530 3531 3532

    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;
3533
    size_t i = 0;
3534 3535 3536 3537
    char *managed_system = phyp_driver->managed_system;

    virCheckFlags(0, NULL);

3538 3539 3540
    if (!(def = virDomainDefParseString(xml, phyp_driver->caps,
                                        phyp_driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_PHYP,
3541 3542 3543 3544
                                        VIR_DOMAIN_XML_SECURE)))
        goto err;

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

3569
 err:
3570
    virDomainDefFree(def);
3571
    virObjectUnref(dom);
3572 3573 3574 3575 3576 3577 3578 3579
    return NULL;
}

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

3580
    return virCapabilitiesFormatXML(phyp_driver->caps);
3581 3582 3583
}

static int
3584 3585
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598
{
    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;

3599
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
3600
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
3601 3602 3603
        return -1;
    }

3604 3605 3606
    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        return 0;

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

    if (exit_status < 0) {
3631
        VIR_ERROR(_
3632 3633 3634 3635 3636 3637
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    " Contact your support to enable this feature."));
    }

    VIR_FREE(ret);
    return 0;
3638 3639

}
3640

3641
static int
3642
phypDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3643 3644 3645 3646
{
    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

3647
static virDrvOpenStatus
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669
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)
3670
{
E
Eric Blake 已提交
3671 3672
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

3676 3677 3678 3679
    return VIR_DRV_OPEN_SUCCESS;
}

static int
3680
phypInterfaceClose(virConnectPtr conn ATTRIBUTE_UNUSED)
3681 3682 3683 3684
{
    return 0;
}

3685
static virDriver phypDriver = {
3686 3687
    .no = VIR_DRV_PHYP,
    .name = "PHYP",
3688 3689
    .connectOpen = phypConnectOpen, /* 0.7.0 */
    .connectClose = phypConnectClose, /* 0.7.0 */
3690
    .connectGetCapabilities = phypConnectGetCapabilities, /* 0.7.3 */
3691 3692 3693
    .connectListDomains = phypConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = phypConnectNumOfDomains, /* 0.7.0 */
    .domainCreateXML = phypDomainCreateXML, /* 0.7.3 */
3694 3695 3696 3697 3698 3699
    .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 */
3700
    .domainDestroyFlags = phypDomainDestroyFlags, /* 0.9.4 */
3701 3702
    .domainGetInfo = phypDomainGetInfo, /* 0.7.0 */
    .domainGetState = phypDomainGetState, /* 0.9.2 */
3703
    .domainSetVcpus = phypDomainSetVcpus, /* 0.7.3 */
3704 3705
    .domainSetVcpusFlags = phypDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = phypDomainGetVcpusFlags, /* 0.8.5 */
3706
    .domainGetMaxVcpus = phypDomainGetMaxVcpus, /* 0.7.3 */
3707
    .domainGetXMLDesc = phypDomainGetXMLDesc, /* 0.7.0 */
3708 3709 3710 3711 3712 3713 3714
    .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 */
3715 3716
};

3717 3718
static virStorageDriver phypStorageDriver = {
    .name = "PHYP",
3719 3720
    .storageOpen = phypStorageOpen, /* 0.8.2 */
    .storageClose = phypStorageClose, /* 0.8.2 */
3721

3722 3723
    .connectNumOfStoragePools = phypConnectNumOfStoragePools, /* 0.8.2 */
    .connectListStoragePools = phypConnectListStoragePools, /* 0.8.2 */
3724
    .storagePoolLookupByName = phypStoragePoolLookupByName, /* 0.8.2 */
3725
    .storagePoolLookupByUUID = phypStoragePoolLookupByUUID, /* 0.8.2 */
3726
    .storagePoolCreateXML = phypStoragePoolCreateXML, /* 0.8.2 */
3727 3728
    .storagePoolDestroy = phypStoragePoolDestroy, /* 0.8.2 */
    .storagePoolGetXMLDesc = phypStoragePoolGetXMLDesc, /* 0.8.2 */
3729 3730 3731
    .storagePoolNumOfVolumes = phypStoragePoolNumOfVolumes, /* 0.8.2 */
    .storagePoolListVolumes = phypStoragePoolListVolumes, /* 0.8.2 */

3732 3733
    .storageVolLookupByName = phypStorageVolLookupByName, /* 0.8.2 */
    .storageVolLookupByPath = phypStorageVolLookupByPath, /* 0.8.2 */
3734
    .storageVolCreateXML = phypStorageVolCreateXML, /* 0.8.2 */
3735 3736
    .storageVolGetXMLDesc = phypStorageVolGetXMLDesc, /* 0.8.2 */
    .storageVolGetPath = phypStorageVolGetPath, /* 0.8.2 */
3737 3738
};

E
Eduardo Otubo 已提交
3739
static virInterfaceDriver phypInterfaceDriver = {
3740
    .name = "PHYP",
3741 3742 3743 3744
    .interfaceOpen = phypInterfaceOpen, /* 0.9.1 */
    .interfaceClose = phypInterfaceClose, /* 0.9.1 */
    .connectNumOfInterfaces = phypConnectNumOfInterfaces, /* 0.9.1 */
    .connectListInterfaces = phypConnectListInterfaces, /* 0.9.1 */
3745 3746 3747 3748
    .interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
    .interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
    .interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
    .interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
3749 3750
};

3751 3752 3753
int
phypRegister(void)
{
3754 3755 3756 3757
    if (virRegisterDriver(&phypDriver) < 0)
        return -1;
    if (virRegisterStorageDriver(&phypStorageDriver) < 0)
        return -1;
E
Eduardo Otubo 已提交
3758
    if (virRegisterInterfaceDriver(&phypInterfaceDriver) < 0)
3759
        return -1;
3760

3761 3762
    return 0;
}