phyp_driver.c 106.2 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2015 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
VIR_LOG_INIT("phyp.phyp_driver");

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
#define LPAR_EXEC_ERR (-1)
#define SSH_CONN_ERR (-2)         /* error while trying to connect to remote host */
#define SSH_CMD_ERR (-3)          /* error while trying to execute the remote cmd */

/* This is the lpar (domain) struct that relates
 * the ID with UUID generated by the API
 * */
typedef struct _lpar lpar_t;
typedef lpar_t *lparPtr;
struct _lpar {
    unsigned char uuid[VIR_UUID_BUFLEN];
    int id;
};

/* Struct that holds how many lpars (domains) we're
 * handling and a pointer to an array of lpar structs
 * */
typedef struct _uuid_table uuid_table_t;
typedef uuid_table_t *uuid_tablePtr;
struct _uuid_table {
    size_t nlpars;
    lparPtr *lpars;
};

/* This is the main structure of the driver
 * */
typedef struct _phyp_driver phyp_driver_t;
typedef phyp_driver_t *phyp_driverPtr;
struct _phyp_driver {
95 96 97
    LIBSSH2_SESSION *session;
    int sock;

98 99 100 101 102 103 104 105 106 107 108 109
    uuid_tablePtr uuid_table;
    virCapsPtr caps;
    virDomainXMLOptionPtr xmlopt;
    int vios_id;

    /* system_type:
     * 0 = hmc
     * 127 = ivm
     * */
    int system_type;
    char *managed_system;
};
110

111 112 113 114
/*
 * URI: phyp://user@[hmc|ivm]/managed_system
 * */

115 116 117 118 119
enum {
    HMC = 0,
    PHYP_IFACENAME_SIZE = 24,
    PHYP_MAC_SIZE = 12,
};
120

121 122 123
static int
waitsocket(int socket_fd, LIBSSH2_SESSION * session)
{
124
    struct pollfd fds[1];
125
    int dir;
126

127 128
    memset(fds, 0, sizeof(fds));
    fds[0].fd = socket_fd;
129

130 131
    /* now make sure we wait in the correct direction */
    dir = libssh2_session_block_directions(session);
132

133
    if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
134
        fds[0].events |= POLLIN;
135

136
    if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
137
        fds[0].events |= POLLOUT;
138

139
    return poll(fds, ARRAY_CARDINALITY(fds), -1);
140
}
141

142 143
/* this function is the layer that manipulates the ssh channel itself
 * and executes the commands on the remote machine */
144 145 146
static char *phypExec(LIBSSH2_SESSION *, const char *, int *, virConnectPtr)
    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
    ATTRIBUTE_NONNULL(4);
147
static char *
148
phypExec(LIBSSH2_SESSION *session, const char *cmd, int *exit_status,
149 150
         virConnectPtr conn)
{
151
    phyp_driverPtr phyp_driver = conn->privateData;
152 153
    LIBSSH2_CHANNEL *channel;
    virBuffer tex_ret = VIR_BUFFER_INITIALIZER;
154 155
    char *buffer = NULL;
    size_t buffer_size = 16384;
156 157
    int exitcode;
    int bytecount = 0;
158
    int sock = phyp_driver->sock;
159
    int rc = 0;
160

161
    if (VIR_ALLOC_N(buffer, buffer_size) < 0)
162 163
        return NULL;

164 165 166 167
    /* 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) {
168 169 170 171 172
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
173 174
    }

175
    if (channel == NULL)
176
        goto err;
177

178 179
    while ((rc = libssh2_channel_exec(channel, cmd)) ==
           LIBSSH2_ERROR_EAGAIN) {
180 181 182 183 184
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
185
    }
186

187
    if (rc != 0)
188
        goto err;
189

190 191 192
    for (;;) {
        /* loop until we block */
        do {
193
            rc = libssh2_channel_read(channel, buffer, buffer_size);
194 195
            if (rc > 0) {
                bytecount += rc;
196
                virBufferAdd(&tex_ret, buffer, -1);
197 198 199
            }
        }
        while (rc > 0);
200

201 202 203
        /* this is due to blocking that would occur otherwise so we loop on
         * this condition */
        if (rc == LIBSSH2_ERROR_EAGAIN) {
204 205 206 207 208
            if (waitsocket(sock, session) < 0 && errno != EINTR) {
                virReportSystemError(errno, "%s",
                                     _("unable to wait on libssh2 socket"));
                goto err;
            }
209 210 211
        } else {
            break;
        }
E
Eduardo Otubo 已提交
212 213
    }

214
    exitcode = 127;
215

216
    while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) {
217 218 219 220 221
        if (waitsocket(sock, session) < 0 && errno != EINTR) {
            virReportSystemError(errno, "%s",
                                 _("unable to wait on libssh2 socket"));
            goto err;
        }
222 223
    }

224
    if (rc == 0)
225
        exitcode = libssh2_channel_get_exit_status(channel);
226

227 228 229
    (*exit_status) = exitcode;
    libssh2_channel_free(channel);
    channel = NULL;
230 231
    VIR_FREE(buffer);

232
    if (virBufferCheckError(&tex_ret) < 0)
233 234
        return NULL;
    return virBufferContentAndReset(&tex_ret);
235

236
 err:
237 238 239 240
    (*exit_status) = SSH_CMD_ERR;
    virBufferFreeAndReset(&tex_ret);
    VIR_FREE(buffer);
    return NULL;
241 242
}

243 244 245 246 247 248 249 250 251 252 253
/* 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;

254
    if (virBufferCheckError(buf) < 0)
255 256 257 258 259 260 261 262 263 264 265 266
        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 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
/* 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;
}

290
static int
291
phypGetSystemType(virConnectPtr conn)
292
{
293 294
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
295 296
    char *ret = NULL;
    int exit_status = 0;
297

298
    ret = phypExec(session, "lshmc -V", &exit_status, conn);
299

300 301
    VIR_FREE(ret);
    return exit_status;
302 303
}

304
static int
305
phypGetVIOSPartitionID(virConnectPtr conn)
306
{
307
    phyp_driverPtr phyp_driver = conn->privateData;
308
    LIBSSH2_SESSION *session = phyp_driver->session;
309 310 311 312
    int system_type = phyp_driver->system_type;
    int id = -1;
    char *managed_system = phyp_driver->managed_system;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
313

314 315
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
316
        virBufferAsprintf(&buf, " -m %s", managed_system);
E
Eric Blake 已提交
317 318
    virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env"
                    "|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'");
E
Eric Blake 已提交
319
    phypExecInt(session, &buf, conn, &id);
320
    return id;
321
}
322

323

324 325 326 327 328
static virCapsPtr
phypCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;
329

330
    if ((caps = virCapabilitiesNew(virArchFromHost(),
331
                                   false, false)) == NULL)
332
        goto no_memory;
333

334 335 336 337 338 339
    /* 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);
340
        VIR_WARN
341
            ("Failed to query host NUMA topology, disabling NUMA capabilities");
342 343
    }

344 345
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "linux",
346
                                         caps->host.arch,
347 348
                                         NULL, NULL, 0, NULL)) == NULL)
        goto no_memory;
349

350 351 352
    if (virCapabilitiesAddGuestDomain(guest,
                                      "phyp", NULL, NULL, 0, NULL) == NULL)
        goto no_memory;
353

354
    return caps;
355

356
 no_memory:
357
    virObjectUnref(caps);
358 359
    return NULL;
}
360

361 362 363 364 365 366 367 368 369
/* 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
370
phypConnectNumOfDomainsGeneric(virConnectPtr conn, unsigned int type)
371 372
{
    phyp_driverPtr phyp_driver = conn->privateData;
373
    LIBSSH2_SESSION *session = phyp_driver->session;
374
    int system_type = phyp_driver->system_type;
375
    int ndom = -1;
376 377 378
    char *managed_system = phyp_driver->managed_system;
    const char *state;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
379

380
    if (type == 0) {
381
        state = "|grep Running";
382
    } else if (type == 1) {
383 384 385 386
        if (system_type == HMC) {
            state = "|grep \"Not Activated\"";
        } else {
            state = "|grep \"Open Firmware\"";
387
        }
388
    } else {
389
        state = " ";
390
    }
391

392 393
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
394 395
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9][0-9]*'",
396
                      state);
E
Eric Blake 已提交
397
    phypExecInt(session, &buf, conn, &ndom);
398
    return ndom;
399 400
}

401 402 403 404 405 406 407 408
/* 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
409 410
phypConnectListDomainsGeneric(virConnectPtr conn, int *ids, int nids,
                              unsigned int type)
411
{
E
Eduardo Otubo 已提交
412
    phyp_driverPtr phyp_driver = conn->privateData;
413
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
414
    int system_type = phyp_driver->system_type;
415
    char *managed_system = phyp_driver->managed_system;
416
    int exit_status = 0;
417
    int got = -1;
418
    char *ret = NULL;
419
    char *line, *next_line;
420
    const char *state;
E
Eduardo Otubo 已提交
421 422
    virBuffer buf = VIR_BUFFER_INITIALIZER;

423 424 425 426 427
    if (type == 0)
        state = "|grep Running";
    else
        state = " ";

E
Eduardo Otubo 已提交
428 429
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
430 431
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'",
432
                      state);
433
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
434

435
    if (exit_status < 0 || ret == NULL)
436
        goto cleanup;
437 438 439 440 441 442 443 444

    /* 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;
445
            goto cleanup;
446
        }
447 448 449 450
        got++;
        line = next_line;
        while (*line == '\n')
            line++; /* skip \n */
451
    }
452

453
 cleanup:
454
    VIR_FREE(ret);
455
    return got;
456 457
}

458 459
static int
phypUUIDTable_WriteFile(virConnectPtr conn)
460
{
461 462
    phyp_driverPtr phyp_driver = conn->privateData;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
463
    size_t i = 0;
464 465 466 467 468
    int fd = -1;
    char local_file[] = "./uuid_table";

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

470
    for (i = 0; i < uuid_table->nlpars; i++) {
471 472 473
        if (safewrite(fd, &uuid_table->lpars[i]->id,
                      sizeof(uuid_table->lpars[i]->id)) !=
            sizeof(uuid_table->lpars[i]->id)) {
474
            VIR_ERROR(_("Unable to write information to local file."));
475 476 477 478 479
            goto err;
        }

        if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) !=
            VIR_UUID_BUFLEN) {
480
            VIR_ERROR(_("Unable to write information to local file."));
481
            goto err;
482 483 484
        }
    }

485 486 487 488 489
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
        goto err;
    }
490 491
    return 0;

492
 err:
493
    VIR_FORCE_CLOSE(fd);
494 495 496
    return -1;
}

497 498
static int
phypUUIDTable_Push(virConnectPtr conn)
499
{
500 501
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
502 503 504 505
    LIBSSH2_CHANNEL *channel = NULL;
    struct stat local_fileinfo;
    char buffer[1024];
    int rc = 0;
506
    FILE *f = NULL;
507 508 509 510
    size_t nread, sent;
    char *ptr;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
511
    int ret = -1;
512

513
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
514
                    NULLSTR(conn->uri->user)) < 0)
515
        goto cleanup;
516

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

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

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

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

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

552 553 554 555 556 557 558 559 560 561 562 563 564
        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);
565

566
    ret = 0;
567

568
 cleanup:
569 570 571 572 573 574 575
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
576 577
    VIR_FORCE_FCLOSE(f);
    return ret;
578 579 580
}

static int
581
phypUUIDTable_RemLpar(virConnectPtr conn, int id)
582
{
E
Eduardo Otubo 已提交
583
    phyp_driverPtr phyp_driver = conn->privateData;
584
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
585
    size_t i = 0;
E
Eduardo Otubo 已提交
586

587 588 589 590 591
    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);
        }
592 593
    }

594
    if (phypUUIDTable_WriteFile(conn) == -1)
595 596
        goto err;

597
    if (phypUUIDTable_Push(conn) == -1)
598 599
        goto err;

600
    return 0;
601

602
 err:
603
    return -1;
604 605
}

606 607
static int
phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id)
608
{
E
Eduardo Otubo 已提交
609
    phyp_driverPtr phyp_driver = conn->privateData;
610
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
611
    lparPtr item = NULL;
E
Eduardo Otubo 已提交
612

613
    if (VIR_ALLOC(item) < 0)
614
        goto err;
615

616 617
    item->id = id;
    memcpy(item->uuid, uuid, VIR_UUID_BUFLEN);
618

619 620
    if (VIR_APPEND_ELEMENT_COPY(uuid_table->lpars, uuid_table->nlpars, item) < 0)
        goto err;
621

622 623
    if (phypUUIDTable_WriteFile(conn) == -1)
        goto err;
624

625
    if (phypUUIDTable_Push(conn) == -1)
626 627
        goto err;

628
    return 0;
629

630
 err:
631
    VIR_FREE(item);
632
    return -1;
633 634
}

635 636
static int
phypUUIDTable_ReadFile(virConnectPtr conn)
637
{
E
Eduardo Otubo 已提交
638
    phyp_driverPtr phyp_driver = conn->privateData;
639
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
640
    size_t i = 0;
641 642 643 644
    int fd = -1;
    char local_file[] = "./uuid_table";
    int rc = 0;
    int id;
645

646
    if ((fd = open(local_file, O_RDONLY)) == -1) {
647
        VIR_WARN("Unable to read information from local file.");
648
        goto err;
649 650
    }

651 652 653
    /* 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++) {
654

655 656
            rc = read(fd, &id, sizeof(int));
            if (rc == sizeof(int)) {
657
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
658 659 660
                    goto err;
                uuid_table->lpars[i]->id = id;
            } else {
661
                VIR_WARN
662
                    ("Unable to read from information from local file.");
663 664
                goto err;
            }
665

666 667
            rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN);
            if (rc != VIR_UUID_BUFLEN) {
668
                VIR_WARN("Unable to read information from local file.");
669 670
                goto err;
            }
671
        }
672
    }
673

674
    VIR_FORCE_CLOSE(fd);
675
    return 0;
676

677
 err:
678
    VIR_FORCE_CLOSE(fd);
679
    return -1;
680 681
}

682 683
static int
phypUUIDTable_Pull(virConnectPtr conn)
684
{
685 686
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
687 688 689 690
    LIBSSH2_CHANNEL *channel = NULL;
    struct stat fileinfo;
    char buffer[1024];
    int rc = 0;
691
    int fd = -1;
692 693 694 695 696 697
    int got = 0;
    int amount = 0;
    int total = 0;
    int sock = 0;
    char local_file[] = "./uuid_table";
    char *remote_file = NULL;
698
    int ret = -1;
E
Eduardo Otubo 已提交
699

700
    if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
701
                    NULLSTR(conn->uri->user)) < 0)
702
        goto cleanup;
703

704 705 706
    /* Trying to stat the remote file. */
    do {
        channel = libssh2_scp_recv(session, remote_file, &fileinfo);
707

708 709 710
        if (!channel) {
            if (libssh2_session_last_errno(session) !=
                LIBSSH2_ERROR_EAGAIN) {
711
                goto cleanup;
712
            } else {
713 714 715
                if (waitsocket(sock, session) < 0 && errno != EINTR) {
                    virReportSystemError(errno, "%s",
                                         _("unable to wait on libssh2 socket"));
716
                    goto cleanup;
717
                }
718 719 720
            }
        }
    } while (!channel);
721

722 723
    /* Creating a new data base based on remote file */
    if ((fd = creat(local_file, 0755)) == -1)
724
        goto cleanup;
725

726 727 728 729
    /* Request a file via SCP */
    while (got < fileinfo.st_size) {
        do {
            amount = sizeof(buffer);
730

731
            if ((fileinfo.st_size - got) < amount)
732
                amount = fileinfo.st_size - got;
E
Eduardo Otubo 已提交
733

734 735 736
            rc = libssh2_channel_read(channel, buffer, amount);
            if (rc > 0) {
                if (safewrite(fd, buffer, rc) != rc)
737
                    VIR_WARN
738
                        ("Unable to write information to local file.");
739

740 741 742 743
                got += rc;
                total += rc;
            }
        } while (rc > 0);
744

745 746 747 748
        if ((rc == LIBSSH2_ERROR_EAGAIN)
            && (got < fileinfo.st_size)) {
            /* this is due to blocking that would occur otherwise
             * so we loop on this condition */
749

750 751 752 753
            /* now we wait */
            if (waitsocket(sock, session) < 0 && errno != EINTR) {
                virReportSystemError(errno, "%s",
                                     _("unable to wait on libssh2 socket"));
754
                goto cleanup;
755
            }
756 757 758 759
            continue;
        }
        break;
    }
760 761 762
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("Could not close %s"),
                             local_file);
763
        goto cleanup;
764
    }
765

766
    ret = 0;
767

768
 cleanup:
769 770 771 772 773 774 775
    if (channel) {
        libssh2_channel_send_eof(channel);
        libssh2_channel_wait_eof(channel);
        libssh2_channel_wait_closed(channel);
        libssh2_channel_free(channel);
        channel = NULL;
    }
776 777
    VIR_FORCE_CLOSE(fd);
    return ret;
778 779
}

780 781
static int
phypUUIDTable_Init(virConnectPtr conn)
782
{
E
Eric Blake 已提交
783
    uuid_tablePtr uuid_table = NULL;
784 785 786 787
    phyp_driverPtr phyp_driver;
    int nids_numdomains = 0;
    int nids_listdomains = 0;
    int *ids = NULL;
788
    size_t i = 0;
E
Eric Blake 已提交
789 790
    int ret = -1;
    bool table_created = false;
E
Eduardo Otubo 已提交
791

792
    if ((nids_numdomains = phypConnectNumOfDomainsGeneric(conn, 2)) < 0)
E
Eric Blake 已提交
793
        goto cleanup;
794

795
    if (VIR_ALLOC_N(ids, nids_numdomains) < 0)
E
Eric Blake 已提交
796
        goto cleanup;
797

798
    if ((nids_listdomains =
799
         phypConnectListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0)
E
Eric Blake 已提交
800
        goto cleanup;
801

802
    /* exit early if there are no domains */
E
Eric Blake 已提交
803 804 805 806 807
    if (nids_numdomains == 0 && nids_listdomains == 0) {
        ret = 0;
        goto cleanup;
    }
    if (nids_numdomains != nids_listdomains) {
808
        VIR_ERROR(_("Unable to determine number of domains."));
E
Eric Blake 已提交
809
        goto cleanup;
810
    }
811

812 813 814
    phyp_driver = conn->privateData;
    uuid_table = phyp_driver->uuid_table;
    uuid_table->nlpars = nids_listdomains;
815

816 817 818
    /* 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 已提交
819
        table_created = true;
820 821
        if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
            for (i = 0; i < uuid_table->nlpars; i++) {
822
                if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
E
Eric Blake 已提交
823
                    goto cleanup;
824
                uuid_table->lpars[i]->id = ids[i];
825

826 827 828 829
                if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0)
                    VIR_WARN("Unable to generate UUID for domain %d",
                             ids[i]);
            }
830
        } else {
E
Eric Blake 已提交
831
            goto cleanup;
832
        }
833

834
        if (phypUUIDTable_WriteFile(conn) == -1)
E
Eric Blake 已提交
835
            goto cleanup;
836

837
        if (phypUUIDTable_Push(conn) == -1)
E
Eric Blake 已提交
838
            goto cleanup;
839 840
    } else {
        if (phypUUIDTable_ReadFile(conn) == -1)
E
Eric Blake 已提交
841
            goto cleanup;
842
    }
843

E
Eric Blake 已提交
844
    ret = 0;
845

846
 cleanup:
E
Eric Blake 已提交
847
    if (ret < 0 && table_created) {
848
        for (i = 0; i < uuid_table->nlpars; i++)
E
Eric Blake 已提交
849 850 851
            VIR_FREE(uuid_table->lpars[i]);
        VIR_FREE(uuid_table->lpars);
    }
852
    VIR_FREE(ids);
E
Eric Blake 已提交
853
    return ret;
854 855
}

856 857
static void
phypUUIDTable_Free(uuid_tablePtr uuid_table)
858
{
859
    size_t i;
860

861 862 863 864 865 866 867 868
    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);
869 870
}

871 872 873 874 875 876 877 878
#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)
879
{
880
    size_t len = strlen(src);
881 882
    size_t i = 0;

883
    if (len == 0)
884
        return false;
885

886 887
    for (i = 0; i < len; i++) {
        switch (src[i]) {
888 889 890 891
        SPECIALCHARACTER_CASES
            return true;
        default:
            continue;
892 893 894
        }
    }

895 896
    return false;
}
897

898 899 900 901 902 903 904 905 906 907
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;

908
    if (VIR_ALLOC_N(dst, len + 1) < 0)
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
        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;
924 925
}

926 927 928
static LIBSSH2_SESSION *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
               int *internal_socket)
929
{
930 931 932 933
    LIBSSH2_SESSION *session;
    const char *hostname = conn->uri->server;
    char *username = NULL;
    char *password = NULL;
934
    int sock = -1;
935 936 937 938 939 940
    int rc;
    struct addrinfo *ai = NULL, *cur;
    struct addrinfo hints;
    int ret;
    char *pubkey = NULL;
    char *pvtkey = NULL;
941
    char *userhome = virGetUserDirectory();
942
    struct stat pvt_stat, pub_stat;
943

944 945
    if (userhome == NULL)
        goto err;
E
Eduardo Otubo 已提交
946

947
    if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0)
948
        goto err;
949

950
    if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0)
951 952
        goto err;

953
    if (conn->uri->user != NULL) {
954
        if (VIR_STRDUP(username, conn->uri->user) < 0)
955 956 957
            goto err;
    } else {
        if (auth == NULL || auth->cb == NULL) {
958 959
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
960 961
            goto err;
        }
962

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

965
        if (username == NULL) {
966 967
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Username request failed"));
968 969 970
            goto err;
        }
    }
971

972 973 974 975
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
976

977 978
    ret = getaddrinfo(hostname, "22", &hints, &ai);
    if (ret != 0) {
979 980
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Error while getting %s address info"), hostname);
981 982
        goto err;
    }
983

984 985 986 987 988
    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) {
989
                freeaddrinfo(ai);
990 991
                goto connected;
            }
992
            VIR_FORCE_CLOSE(sock);
993 994 995
        }
        cur = cur->ai_next;
    }
996

997 998
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to connect to %s"), hostname);
999 1000
    freeaddrinfo(ai);
    goto err;
1001

1002
 connected:
1003

1004
    (*internal_socket) = sock;
1005

1006 1007 1008
    /* Create a session instance */
    session = libssh2_session_init();
    if (!session)
1009 1010
        goto err;

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

1014
    while ((rc = libssh2_session_startup(session, sock)) ==
1015
           LIBSSH2_ERROR_EAGAIN);
1016
    if (rc) {
1017 1018
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failure establishing SSH session."));
1019 1020
        goto disconnect;
    }
1021

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

1028 1029 1030 1031 1032
    while ((rc =
            libssh2_userauth_publickey_fromfile(session, username,
                                                pubkey,
                                                pvtkey,
                                                NULL)) ==
1033
           LIBSSH2_ERROR_EAGAIN);
1034

1035
 keyboard_interactive:
1036 1037 1038 1039
    if (rc == LIBSSH2_ERROR_SOCKET_NONE
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
        || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
        if (auth == NULL || auth->cb == NULL) {
1040 1041
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("No authentication callback provided."));
1042 1043
            goto disconnect;
        }
1044

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

1047
        if (password == NULL) {
1048 1049
            virReportError(VIR_ERR_AUTH_FAILED, "%s",
                           _("Password request failed"));
1050 1051
            goto disconnect;
        }
1052

1053 1054 1055
        while ((rc =
                libssh2_userauth_password(session, username,
                                          password)) ==
1056
               LIBSSH2_ERROR_EAGAIN);
1057

1058
        if (rc) {
1059 1060
            virReportError(VIR_ERR_AUTH_FAILED,
                           "%s", _("Authentication failed"));
1061
            goto disconnect;
1062
        } else {
1063
            goto exit;
1064
        }
1065

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

1069 1070
    } else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
               || rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
1071 1072 1073
        goto err;
    }

1074
 disconnect:
1075 1076
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1077
 err:
1078
    VIR_FORCE_CLOSE(sock);
1079 1080 1081 1082 1083
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
1084
    return NULL;
1085

1086
 exit:
1087 1088 1089 1090 1091 1092
    VIR_FREE(userhome);
    VIR_FREE(pubkey);
    VIR_FREE(pvtkey);
    VIR_FREE(username);
    VIR_FREE(password);
    return session;
1093 1094
}

1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120

static int
phypDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
                       virCapsPtr caps ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}


static int
phypDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                             const virDomainDef *def ATTRIBUTE_UNUSED,
                             virCapsPtr caps ATTRIBUTE_UNUSED,
                             void *opaque ATTRIBUTE_UNUSED)
{
    return 0;
}


virDomainDefParserConfig virPhypDriverDomainDefParserConfig = {
    .devicesPostParseCallback = phypDomainDeviceDefPostParse,
    .domainPostParseCallback = phypDomainDefPostParse,
};


1121
static virDrvOpenStatus
1122 1123
phypConnectOpen(virConnectPtr conn,
                virConnectAuthPtr auth, unsigned int flags)
1124 1125
{
    LIBSSH2_SESSION *session = NULL;
1126
    int internal_socket = -1;
1127 1128 1129 1130
    uuid_tablePtr uuid_table = NULL;
    phyp_driverPtr phyp_driver = NULL;
    char *char_ptr;
    char *managed_system = NULL;
E
Eduardo Otubo 已提交
1131

E
Eric Blake 已提交
1132 1133
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1134 1135 1136 1137 1138 1139 1140
    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) {
1141 1142
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing server name in phyp:// URI"));
1143 1144 1145
        return VIR_DRV_OPEN_ERROR;
    }

1146
    if (VIR_ALLOC(phyp_driver) < 0)
1147
        goto failure;
1148

1149
    phyp_driver->sock = -1;
1150

1151
    if (VIR_ALLOC(uuid_table) < 0)
1152
        goto failure;
1153

1154 1155
    if (conn->uri->path) {
        /* need to shift one byte in order to remove the first "/" of URI component */
1156 1157
        if (VIR_STRDUP(managed_system,
                       conn->uri->path + (conn->uri->path[0] == '/')) < 0)
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
            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';

1168
        if (contains_specialcharacters(conn->uri->path)) {
1169 1170 1171
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s",
                           _("Error parsing 'path'. Invalid characters."));
1172 1173 1174 1175 1176
            goto failure;
        }
    }

    if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
1177 1178
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Error while opening SSH session."));
1179 1180 1181
        goto failure;
    }

1182 1183
    phyp_driver->session = session;
    phyp_driver->sock = internal_socket;
1184 1185 1186 1187 1188 1189 1190 1191

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

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

    phyp_driver->uuid_table = uuid_table;
1192
    if ((phyp_driver->caps = phypCapsInit()) == NULL)
1193
        goto failure;
1194

1195 1196
    if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig,
                                                      NULL, NULL)))
1197 1198
        goto failure;

1199
    conn->privateData = phyp_driver;
1200

1201 1202
    if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
        goto failure;
1203

1204 1205
    if (phypUUIDTable_Init(conn) == -1)
        goto failure;
1206

1207 1208 1209 1210 1211 1212 1213
    if (phyp_driver->system_type == HMC) {
        if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
            goto failure;
    }

    return VIR_DRV_OPEN_SUCCESS;

1214
 failure:
1215 1216
    VIR_FREE(managed_system);

1217
    if (phyp_driver != NULL) {
1218
        virObjectUnref(phyp_driver->caps);
1219
        virObjectUnref(phyp_driver->xmlopt);
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
        VIR_FREE(phyp_driver);
    }

    phypUUIDTable_Free(uuid_table);

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

1230
    VIR_FORCE_CLOSE(internal_socket);
1231 1232

    return VIR_DRV_OPEN_ERROR;
1233 1234 1235
}

static int
1236
phypConnectClose(virConnectPtr conn)
1237
{
1238
    phyp_driverPtr phyp_driver = conn->privateData;
1239
    LIBSSH2_SESSION *session = phyp_driver->session;
1240

1241 1242
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1243

1244
    virObjectUnref(phyp_driver->caps);
1245
    virObjectUnref(phyp_driver->xmlopt);
1246 1247 1248
    phypUUIDTable_Free(phyp_driver->uuid_table);
    VIR_FREE(phyp_driver->managed_system);
    VIR_FREE(phyp_driver);
1249

1250
    VIR_FORCE_CLOSE(phyp_driver->sock);
1251 1252
    return 0;
}
1253 1254


1255
static int
1256
phypConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1257 1258 1259 1260
{
    /* Phyp uses an SSH tunnel, so is always encrypted */
    return 1;
}
1261

1262 1263

static int
1264
phypConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1265 1266 1267
{
    /* Phyp uses an SSH tunnel, so is always secure */
    return 1;
1268 1269
}

1270 1271

static int
1272
phypConnectIsAlive(virConnectPtr conn)
1273
{
1274
    phyp_driverPtr phyp_driver = conn->privateData;
1275 1276 1277 1278
    /* 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.
     */
1279
    if (phyp_driver->session)
1280 1281 1282 1283 1284 1285
        return 1;
    else
        return 0;
}


1286
static int
1287
phypDomainIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
1288 1289 1290
{
    return 0;
}
1291 1292

/* return the lpar_id given a name and a managed system name */
1293
static int
1294 1295
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
              const char *name, virConnectPtr conn)
1296
{
1297
    phyp_driverPtr phyp_driver = conn->privateData;
E
Eduardo Otubo 已提交
1298
    int system_type = phyp_driver->system_type;
1299
    int lpar_id = -1;
E
Eduardo Otubo 已提交
1300 1301
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1302
    virBufferAddLit(&buf, "lssyscfg -r lpar");
E
Eduardo Otubo 已提交
1303
    if (system_type == HMC)
1304 1305
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_names=%s -F lpar_id", name);
E
Eric Blake 已提交
1306
    phypExecInt(session, &buf, conn, &lpar_id);
1307
    return lpar_id;
1308 1309
}

1310 1311 1312 1313
/* 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)
1314 1315
{
    phyp_driverPtr phyp_driver = conn->privateData;
1316 1317 1318 1319
    int system_type = phyp_driver->system_type;
    char *ret = NULL;
    int exit_status = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1320

1321 1322
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
1323 1324
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --filter lpar_ids=%d -F name", lpar_id);
1325
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1326

1327
    if (exit_status < 0)
1328 1329
        VIR_FREE(ret);
    return ret;
1330 1331
}

1332 1333 1334 1335 1336 1337 1338 1339 1340

/* 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)
1341 1342
{
    phyp_driverPtr phyp_driver = conn->privateData;
1343 1344
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
1345
    size_t i = 0;
1346

1347 1348
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
1349
            memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
1350 1351 1352
            return 0;
        }
    }
1353

1354
    return -1;
1355 1356
}

1357 1358 1359 1360 1361 1362 1363 1364
/*
 * type:
 * 0 - maxmem
 * 1 - memory
 * */
static unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
               int type)
1365
{
1366
    phyp_driverPtr phyp_driver = conn->privateData;
1367
    LIBSSH2_SESSION *session = phyp_driver->session;
1368 1369 1370
    int system_type = phyp_driver->system_type;
    int memory = 0;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1371

1372 1373
    if (type != 1 && type != 0)
        return 0;
1374

1375 1376
    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1377 1378
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1379 1380
                      " -r mem --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_mem" : "curr_max_mem", lpar_id);
E
Eric Blake 已提交
1381
    phypExecInt(session, &buf, conn, &memory);
1382
    return memory;
1383 1384
}

1385 1386 1387
static unsigned long
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
                      int lpar_id, int type)
1388
{
1389
    phyp_driverPtr phyp_driver = conn->privateData;
1390
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
1391
    int system_type = phyp_driver->system_type;
1392
    int vcpus = 0;
E
Eduardo Otubo 已提交
1393
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1394

1395
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1396
    if (system_type == HMC)
1397 1398
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1399 1400
                      " -r proc --level lpar -F %s --filter lpar_ids=%d",
                      type ? "curr_max_procs" : "curr_procs", lpar_id);
E
Eric Blake 已提交
1401
    phypExecInt(session, &buf, conn, &vcpus);
1402
    return vcpus;
1403
}
1404

1405 1406 1407 1408
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
    return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
1409 1410
}

1411
static int
1412
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
1413 1414 1415
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;
1416

1417
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1418
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1419 1420 1421
        return -1;
    }

1422 1423 1424
    return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}

1425
static int
1426
phypDomainGetMaxVcpus(virDomainPtr dom)
1427 1428 1429 1430 1431
{
    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

1432 1433 1434
static int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
                  const char *lpar_name)
1435
{
1436
    phyp_driverPtr phyp_driver = conn->privateData;
1437
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
1438
    int system_type = phyp_driver->system_type;
1439
    int remote_slot = -1;
E
Eduardo Otubo 已提交
1440 1441
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1442
    virBufferAddLit(&buf, "lshwres");
E
Eduardo Otubo 已提交
1443
    if (system_type == HMC)
1444 1445
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1446
                      "remote_slot_num --filter lpar_names=%s", lpar_name);
E
Eric Blake 已提交
1447
    phypExecInt(session, &buf, conn, &remote_slot);
1448
    return remote_slot;
1449 1450
}

1451 1452 1453 1454 1455 1456
/* 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)
1457 1458
{
    phyp_driverPtr phyp_driver = conn->privateData;
1459
    LIBSSH2_SESSION *session = phyp_driver->session;
1460 1461 1462 1463 1464 1465 1466
    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;
1467

1468 1469 1470 1471 1472 1473
    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        return NULL;

    virBufferAddLit(&buf, "lshwres");
    if (system_type == HMC)
1474 1475
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
1476
                      "backing_devices --filter slots=%d", remote_slot);
1477
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1478

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

1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
    /* 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
1496
            goto cleanup;
1497

1498
        if (VIR_STRDUP(backing_device, char_ptr) < 0)
1499
            goto cleanup;
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
    } else {
        backing_device = ret;
        ret = NULL;
    }

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

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

1510
 cleanup:
1511
    VIR_FREE(ret);
1512

1513
    return backing_device;
1514 1515 1516 1517 1518 1519
}

static char *
phypGetLparProfile(virConnectPtr conn, int lpar_id)
{
    phyp_driverPtr phyp_driver = conn->privateData;
1520
    LIBSSH2_SESSION *session = phyp_driver->session;
1521 1522 1523 1524 1525 1526 1527 1528
    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)
1529 1530
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1531 1532
                      " -r prof --filter lpar_ids=%d -F name|head -n 1",
                      lpar_id);
1533
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1534

1535
    if (exit_status < 0)
1536 1537
        VIR_FREE(ret);
    return ret;
1538 1539 1540 1541 1542 1543
}

static int
phypGetVIOSNextSlotNumber(virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
1544
    LIBSSH2_SESSION *session = phyp_driver->session;
1545 1546 1547 1548
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
    char *profile = NULL;
1549
    int slot = -1;
1550 1551 1552
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1553
        VIR_ERROR(_("Unable to get VIOS profile name."));
1554
        return -1;
1555 1556 1557 1558 1559
    }

    virBufferAddLit(&buf, "lssyscfg");

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

1562
    virBufferAsprintf(&buf, " -r prof --filter "
1563 1564 1565 1566 1567
                      "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 已提交
1568 1569 1570
    if (phypExecInt(session, &buf, conn, &slot) < 0)
        return -1;
    return slot + 1;
1571 1572 1573 1574 1575
}

static int
phypCreateServerSCSIAdapter(virConnectPtr conn)
{
1576
    int result = -1;
1577
    phyp_driverPtr phyp_driver = conn->privateData;
1578
    LIBSSH2_SESSION *session = phyp_driver->session;
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
    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))) {
1592
        VIR_ERROR(_("Unable to get VIOS name"));
1593
        goto cleanup;
1594 1595 1596
    }

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1597
        VIR_ERROR(_("Unable to get VIOS profile name."));
1598
        goto cleanup;
1599 1600 1601
    }

    if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
1602
        VIR_ERROR(_("Unable to get free slot number"));
1603
        goto cleanup;
1604 1605 1606 1607 1608 1609 1610
    }

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1611 1612
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof --filter lpar_ids=%d,profile_names=%s"
1613 1614
                      " -F virtual_scsi_adapters|sed -e s/\\\"//g",
                      vios_id, profile);
1615
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1616 1617

    if (exit_status < 0 || ret == NULL)
1618
        goto cleanup;
1619 1620 1621 1622 1623 1624

    /* 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)
1625 1626
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d,"
1627 1628
                      "\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'",
                      vios_name, vios_id, ret, slot);
1629
    VIR_FREE(ret);
1630
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1631 1632

    if (exit_status < 0 || ret == NULL)
1633
        goto cleanup;
1634 1635 1636 1637 1638 1639

    /* 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)
1640 1641
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1642 1643
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      vios_name, slot);
1644
    VIR_FREE(ret);
1645
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1646 1647

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

1650
    result = 0;
1651

1652
 cleanup:
1653 1654 1655
    VIR_FREE(profile);
    VIR_FREE(vios_name);
    VIR_FREE(ret);
1656 1657

    return result;
1658 1659 1660 1661 1662 1663
}

static char *
phypGetVIOSFreeSCSIAdapter(virConnectPtr conn)
{
    phyp_driverPtr phyp_driver = conn->privateData;
1664
    LIBSSH2_SESSION *session = phyp_driver->session;
1665 1666 1667 1668 1669 1670 1671 1672
    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)
1673
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1674 1675
                          managed_system, vios_id);

1676
    virBufferAddLit(&buf, "lsmap -all -field svsa backing -fmt , ");
1677 1678 1679 1680

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

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

1684
    if (exit_status < 0)
1685 1686
        VIR_FREE(ret);
    return ret;
1687 1688 1689 1690
}


static int
1691
phypDomainAttachDevice(virDomainPtr domain, const char *xml)
1692
{
1693
    int result = -1;
1694 1695
    virConnectPtr conn = domain->conn;
    phyp_driverPtr phyp_driver = domain->conn->privateData;
1696
    LIBSSH2_SESSION *session = phyp_driver->session;
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
    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;

1711
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
1712 1713
        goto cleanup;

1714
    domain_name = escape_specialcharacters(domain->name);
1715

1716
    if (domain_name == NULL)
1717
        goto cleanup;
1718

1719
    if (VIR_STRDUP(def->os.type, "aix") < 0)
1720
        goto cleanup;
1721

1722
    dev = virDomainDeviceDefParse(xml, def, phyp_driver->caps, NULL,
1723
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
1724
    if (!dev)
1725
        goto cleanup;
1726 1727 1728 1729

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1730
        VIR_ERROR(_("Unable to get VIOS name"));
1731
        goto cleanup;
1732 1733 1734 1735 1736 1737 1738 1739
    }

    /* 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) {
1740
            VIR_ERROR(_("Unable to create new virtual adapter"));
1741
            goto cleanup;
1742 1743
        } else {
            if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
1744
                VIR_ERROR(_("Unable to create new virtual adapter"));
1745
                goto cleanup;
1746 1747 1748 1749 1750
            }
        }
    }

    if (system_type == HMC)
1751
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1752 1753
                          managed_system, vios_id);

1754
    virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
1755
                      virDomainDiskGetSource(dev->data.disk), scsi_adapter);
1756 1757 1758

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1759
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1760 1761

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

    if (!(profile = phypGetLparProfile(conn, domain->id))) {
1765
        VIR_ERROR(_("Unable to get VIOS profile name."));
1766
        goto cleanup;
1767 1768 1769 1770 1771 1772
    }

    /* Let's get the slot number for the adapter we just created
     * */
    virBufferAddLit(&buf, "lshwres -r virtualio --rsubtype scsi");
    if (system_type == HMC)
1773 1774
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1775
                      " slot_num,backing_device|grep %s|cut -d, -f1",
1776
                      virDomainDiskGetSource(dev->data.disk));
E
Eric Blake 已提交
1777
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1778
        goto cleanup;
1779 1780 1781 1782 1783 1784

    /* Listing all the virtual_scsi_adapter interfaces, the new adapter must
     * be appended to this list
     * */
    virBufferAddLit(&buf, "lssyscfg");
    if (system_type == HMC)
1785 1786
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1787 1788 1789
                      " -r prof --filter lpar_ids=%d,profile_names=%s"
                      " -F virtual_scsi_adapters|sed -e 's/\"//g'",
                      vios_id, profile);
1790
    VIR_FREE(ret);
1791
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1792 1793

    if (exit_status < 0 || ret == NULL)
1794
        goto cleanup;
1795 1796 1797 1798 1799 1800

    /* 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)
1801 1802
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1803 1804 1805 1806
                      " -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 已提交
1807
    if (phypExecInt(session, &buf, conn, &slot) < 0)
1808
        goto cleanup;
1809 1810 1811 1812 1813 1814

    /* 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)
1815 1816
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
1817 1818
                      " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
                      domain_name, slot);
1819
    VIR_FREE(ret);
1820
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1821 1822

    if (exit_status < 0 || ret == NULL) {
1823
        VIR_ERROR(_
1824 1825
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    "Contact your support to enable this feature."));
1826
        goto cleanup;
1827 1828
    }

1829
    result = 0;
1830

1831
 cleanup:
1832
    VIR_FREE(ret);
1833 1834
    virDomainDeviceDefFree(dev);
    virDomainDefFree(def);
1835 1836
    VIR_FREE(vios_name);
    VIR_FREE(scsi_adapter);
1837 1838 1839 1840
    VIR_FREE(profile);
    VIR_FREE(domain_name);

    return result;
1841 1842
}

1843
static char *
1844
phypStorageVolGetKey(virConnectPtr conn, const char *name)
1845 1846
{
    phyp_driverPtr phyp_driver = conn->privateData;
1847
    LIBSSH2_SESSION *session = phyp_driver->session;
1848 1849 1850 1851 1852 1853 1854 1855
    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)
1856
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1857 1858
                          managed_system, vios_id);

1859
    virBufferAsprintf(&buf, "lslv %s -field lvid", name);
1860 1861 1862 1863

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

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

1867
    if (exit_status < 0)
1868 1869
        VIR_FREE(ret);
    return ret;
1870 1871 1872 1873 1874 1875
}

static char *
phypGetStoragePoolDevice(virConnectPtr conn, char *name)
{
    phyp_driverPtr phyp_driver = conn->privateData;
1876
    LIBSSH2_SESSION *session = phyp_driver->session;
1877 1878 1879 1880 1881 1882 1883 1884
    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)
1885
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1886 1887
                          managed_system, vios_id);

1888
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
1889 1890 1891 1892

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

1893
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
1894
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1895

1896
    if (exit_status < 0)
1897 1898
        VIR_FREE(ret);
    return ret;
1899 1900 1901 1902 1903 1904
}

static unsigned long int
phypGetStoragePoolSize(virConnectPtr conn, char *name)
{
    phyp_driverPtr phyp_driver = conn->privateData;
1905
    LIBSSH2_SESSION *session = phyp_driver->session;
1906 1907 1908
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
1909
    int sp_size = -1;
1910 1911 1912
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
1913
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1914 1915
                          managed_system, vios_id);

1916
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
1917 1918 1919 1920

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

1921
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
E
Eric Blake 已提交
1922
    phypExecInt(session, &buf, conn, &sp_size);
1923
    return sp_size;
1924 1925
}

1926
static char *
1927
phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname,
1928
                unsigned int capacity)
1929 1930
{
    phyp_driverPtr phyp_driver = conn->privateData;
1931
    LIBSSH2_SESSION *session = phyp_driver->session;
1932 1933 1934 1935 1936 1937
    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;
1938
    char *key = NULL;
1939 1940

    if (system_type == HMC)
1941
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1942 1943
                          managed_system, vios_id);

1944
    virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
1945 1946 1947

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1948
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1949 1950

    if (exit_status < 0) {
1951
        VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
1952
        goto cleanup;
1953 1954
    }

1955
    key = phypStorageVolGetKey(conn, lvname);
1956

1957
 cleanup:
1958 1959
    VIR_FREE(ret);

1960
    return key;
1961 1962 1963
}

static virStorageVolPtr
1964
phypStorageVolLookupByName(virStoragePoolPtr pool, const char *volname)
1965
{
1966 1967
    char *key;
    virStorageVolPtr vol;
1968

1969
    key = phypStorageVolGetKey(pool->conn, volname);
1970

1971
    if (key == NULL)
1972 1973
        return NULL;

1974
    vol = virGetStorageVol(pool->conn, pool->name, volname, key, NULL, NULL);
1975 1976 1977 1978

    VIR_FREE(key);

    return vol;
1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
}

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

    virStorageVolDefPtr voldef = NULL;
    virStoragePoolDefPtr spdef = NULL;
    virStorageVolPtr vol = NULL;
1990
    virStorageVolPtr dup_vol = NULL;
1991 1992
    char *key = NULL;

1993
    if (VIR_ALLOC(spdef) < 0)
1994 1995 1996 1997 1998 1999 2000
        return NULL;

    /* Filling spdef manually
     * */
    if (pool->name != NULL) {
        spdef->name = pool->name;
    } else {
2001
        VIR_ERROR(_("Unable to determine storage pool's name."));
2002 2003 2004 2005
        goto err;
    }

    if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2006
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2007 2008 2009 2010 2011
        goto err;
    }

    if ((spdef->capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2012
        VIR_ERROR(_("Unable to determine storage pools's size."));
2013 2014 2015
        goto err;
    }

J
Ján Tomko 已提交
2016
    /* Information not available */
2017 2018 2019 2020 2021 2022
    spdef->allocation = 0;
    spdef->available = 0;

    spdef->source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
2023
    if ((spdef->source.adapter.data.scsi_host.name =
2024
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2025
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2026 2027 2028 2029
        goto err;
    }

    if ((voldef = virStorageVolDefParseString(spdef, xml)) == NULL) {
2030
        VIR_ERROR(_("Error parsing volume XML."));
2031 2032 2033 2034
        goto err;
    }

    /* checking if this name already exists on this system */
2035
    if ((dup_vol = phypStorageVolLookupByName(pool, voldef->name)) != NULL) {
2036
        VIR_ERROR(_("StoragePool name already exists."));
2037
        virObjectUnref(dup_vol);
2038 2039 2040 2041 2042 2043 2044
        goto err;
    }

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

2049
    if (!voldef->target.capacity) {
2050
        VIR_ERROR(_("Capacity cannot be empty."));
2051 2052 2053
        goto err;
    }

2054
    key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
2055
                          voldef->target.capacity);
2056 2057

    if (key == NULL)
2058 2059 2060 2061
        goto err;

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

2065 2066
    VIR_FREE(key);

2067 2068
    return vol;

2069
 err:
2070
    VIR_FREE(key);
2071 2072
    virStorageVolDefFree(voldef);
    virStoragePoolDefFree(spdef);
2073
    virObjectUnref(vol);
2074 2075 2076 2077
    return NULL;
}

static char *
2078
phypStorageVolGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp)
2079 2080 2081
{
    virConnectPtr conn = vol->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
2082
    LIBSSH2_SESSION *session = phyp_driver->session;
2083 2084 2085 2086 2087 2088 2089 2090
    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)
2091
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2092 2093
                          managed_system, vios_id);

2094
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
2095 2096 2097 2098

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

2099
    virBufferAddLit(&buf, "|sed 1d");
2100
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2101

2102
    if (exit_status < 0)
2103 2104
        VIR_FREE(ret);
    return ret;
2105 2106 2107
}

static virStorageVolPtr
2108
phypStorageVolLookupByPath(virConnectPtr conn, const char *volname)
2109 2110
{
    phyp_driverPtr phyp_driver = conn->privateData;
2111
    LIBSSH2_SESSION *session = phyp_driver->session;
2112 2113 2114 2115
    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;
2116
    char *ret = NULL;
2117 2118
    char *key = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2119
    virStorageVolPtr vol = NULL;
2120 2121

    if (system_type == HMC)
2122
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2123 2124
                          managed_system, vios_id);

2125
    virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
2126 2127 2128 2129

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

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

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

2136
    key = phypStorageVolGetKey(conn, volname);
2137

2138
    if (key == NULL)
2139
        goto cleanup;
2140

2141
    vol = virGetStorageVol(conn, ret, volname, key, NULL, NULL);
2142

2143
 cleanup:
2144
    VIR_FREE(ret);
2145 2146 2147
    VIR_FREE(key);

    return vol;
2148 2149 2150 2151 2152 2153
}

static int
phypGetStoragePoolUUID(virConnectPtr conn, unsigned char *uuid,
                       const char *name)
{
2154
    int result = -1;
2155
    phyp_driverPtr phyp_driver = conn->privateData;
2156
    LIBSSH2_SESSION *session = phyp_driver->session;
2157 2158 2159 2160 2161 2162 2163 2164
    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)
2165
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2166 2167
                          managed_system, vios_id);

2168
    virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
2169 2170 2171 2172

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

2173
    virBufferAddLit(&buf, "|sed '1,2d'");
2174
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2175 2176

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

2179
    if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
2180
        goto cleanup;
2181

2182
    result = 0;
2183

2184
 cleanup:
2185
    VIR_FREE(ret);
2186 2187

    return result;
2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
}

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

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

2198
    return virGetStoragePool(conn, name, uuid, NULL, NULL);
2199 2200 2201
}

static char *
2202
phypStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
2203
{
2204 2205 2206
    virStorageVolDef voldef;
    virStoragePoolDef pool;
    virStoragePoolPtr sp;
2207
    char *xml = NULL;
2208

2209 2210 2211
    virCheckFlags(0, NULL);

    memset(&voldef, 0, sizeof(virStorageVolDef));
2212
    memset(&pool, 0, sizeof(virStoragePoolDef));
2213

2214
    sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
2215 2216

    if (!sp)
2217
        goto cleanup;
2218 2219 2220 2221

    if (sp->name != NULL) {
        pool.name = sp->name;
    } else {
2222
        VIR_ERROR(_("Unable to determine storage sp's name."));
2223
        goto cleanup;
2224 2225
    }

2226
    if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
2227
        VIR_ERROR(_("Unable to determine storage sp's uuid."));
2228
        goto cleanup;
2229 2230 2231
    }

    if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
2232
        VIR_ERROR(_("Unable to determine storage sps's size."));
2233
        goto cleanup;
2234 2235
    }

J
Ján Tomko 已提交
2236
    /* Information not available */
2237 2238 2239 2240 2241
    pool.allocation = 0;
    pool.available = 0;

    pool.source.ndevice = 1;

2242
    if ((pool.source.adapter.data.scsi_host.name =
2243
         phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) {
2244
        VIR_ERROR(_("Unable to determine storage sps's source adapter."));
2245
        goto cleanup;
2246 2247
    }

2248
    if (vol->name != NULL) {
2249
        voldef.name = vol->name;
2250
    } else {
2251
        VIR_ERROR(_("Unable to determine storage pool's name."));
2252
        goto cleanup;
2253 2254
    }

2255
    if (VIR_STRDUP(voldef.key, vol->key) < 0)
2256
        goto cleanup;
2257 2258 2259

    voldef.type = VIR_STORAGE_POOL_LOGICAL;

2260 2261 2262 2263
    xml = virStorageVolDefFormat(&pool, &voldef);

    VIR_FREE(voldef.key);

2264
 cleanup:
2265
    virObjectUnref(sp);
2266
    return xml;
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277
}

/* 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 *
2278
phypStorageVolGetPath(virStorageVolPtr vol)
2279 2280 2281
{
    virConnectPtr conn = vol->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
2282
    LIBSSH2_SESSION *session = phyp_driver->session;
2283 2284 2285 2286
    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;
2287
    char *ret = NULL;
2288 2289
    char *path = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2290
    char *pv;
2291 2292

    if (system_type == HMC)
2293
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2294 2295
                          managed_system, vios_id);

2296
    virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
2297 2298 2299 2300

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

2301
    virBufferAsprintf(&buf,
2302
                      "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2303
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2304

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

2308
    pv = phypStorageVolGetPhysicalVolumeByStoragePool(vol, ret);
2309

2310 2311
    if (!pv)
        goto cleanup;
2312

2313
    if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0)
2314
        goto cleanup;
2315

2316
 cleanup:
2317
    VIR_FREE(ret);
2318
    VIR_FREE(path);
2319 2320

    return path;
2321 2322 2323 2324 2325 2326
}

static int
phypStoragePoolListVolumes(virStoragePoolPtr pool, char **const volumes,
                           int nvolumes)
{
2327
    bool success = false;
2328 2329
    virConnectPtr conn = pool->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
2330
    LIBSSH2_SESSION *session = phyp_driver->session;
2331 2332 2333 2334 2335
    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;
2336
    size_t i;
2337 2338
    char *ret = NULL;
    char *volumes_list = NULL;
E
Eric Blake 已提交
2339
    char *char_ptr = NULL;
2340 2341 2342
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2343
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2344 2345
                          managed_system, vios_id);

2346
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2347 2348 2349 2350

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

2351
    virBufferAddLit(&buf, "|sed '1,2d'");
2352
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2353 2354

    /* I need to parse the textual return in order to get the volumes */
2355
    if (exit_status < 0 || ret == NULL) {
2356
        goto cleanup;
2357
    } else {
2358 2359 2360
        volumes_list = ret;

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

E
Eric Blake 已提交
2363 2364
            if (char_ptr) {
                *char_ptr = '\0';
2365
                if (VIR_STRDUP(volumes[got++], volumes_list) < 0)
2366
                    goto cleanup;
E
Eric Blake 已提交
2367 2368
                char_ptr++;
                volumes_list = char_ptr;
2369
            } else {
2370
                break;
2371
            }
2372 2373 2374
        }
    }

2375 2376
    success = true;

2377
 cleanup:
2378 2379 2380 2381 2382 2383
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(volumes[i]);

        got = -1;
    }
2384
    VIR_FREE(ret);
2385
    return got;
2386 2387 2388 2389 2390 2391 2392
}

static int
phypStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
    virConnectPtr conn = pool->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
2393
    LIBSSH2_SESSION *session = phyp_driver->session;
2394
    int system_type = phyp_driver->system_type;
2395
    int nvolumes = -1;
2396 2397 2398 2399 2400
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (system_type == HMC)
2401
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2402
                          managed_system, vios_id);
2403
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2404 2405
    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2406
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2407 2408
    if (phypExecInt(session, &buf, conn, &nvolumes) < 0)
        return -1;
2409 2410

    /* We need to remove 2 line from the header text output */
E
Eric Blake 已提交
2411
    return nvolumes - 2;
2412 2413 2414
}

static int
2415
phypStoragePoolDestroy(virStoragePoolPtr pool)
2416
{
2417
    int result = -1;
2418 2419
    virConnectPtr conn = pool->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
2420
    LIBSSH2_SESSION *session = phyp_driver->session;
2421 2422 2423 2424 2425 2426 2427 2428
    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)
2429
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2430 2431
                          managed_system, vios_id);

2432
    virBufferAsprintf(&buf, "rmsp %s", pool->name);
2433 2434 2435

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2436
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2437 2438

    if (exit_status < 0) {
2439
        VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
2440
        goto cleanup;
2441 2442
    }

2443
    result = 0;
2444

2445
 cleanup:
2446
    VIR_FREE(ret);
2447 2448

    return result;
2449 2450 2451 2452 2453
}

static int
phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
{
2454
    int result = -1;
2455
    phyp_driverPtr phyp_driver = conn->privateData;
2456
    LIBSSH2_SESSION *session = phyp_driver->session;
2457 2458 2459 2460 2461 2462 2463 2464
    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;

2465 2466 2467 2468 2469 2470 2471
    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;
    }

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

2476
    virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
2477
                      source.adapter.data.scsi_host.name);
2478 2479 2480

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2481
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2482 2483

    if (exit_status < 0) {
2484
        VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
2485
        goto cleanup;
2486 2487
    }

2488
    result = 0;
2489

2490
 cleanup:
2491
    VIR_FREE(ret);
2492 2493

    return result;
2494 2495 2496 2497

}

static int
2498
phypConnectNumOfStoragePools(virConnectPtr conn)
2499 2500
{
    phyp_driverPtr phyp_driver = conn->privateData;
2501
    LIBSSH2_SESSION *session = phyp_driver->session;
2502
    int system_type = phyp_driver->system_type;
2503
    int nsp = -1;
2504 2505 2506 2507 2508
    char *managed_system = phyp_driver->managed_system;
    int vios_id = phyp_driver->vios_id;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

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

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

2517
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2518
    phypExecInt(session, &buf, conn, &nsp);
2519
    return nsp;
2520 2521 2522
}

static int
2523
phypConnectListStoragePools(virConnectPtr conn, char **const pools, int npools)
2524
{
2525
    bool success = false;
2526
    phyp_driverPtr phyp_driver = conn->privateData;
2527
    LIBSSH2_SESSION *session = phyp_driver->session;
2528 2529 2530 2531 2532
    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;
2533
    size_t i;
2534 2535
    char *ret = NULL;
    char *storage_pools = NULL;
E
Eric Blake 已提交
2536
    char *char_ptr = NULL;
2537 2538 2539
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

2543
    virBufferAddLit(&buf, "lsvg");
2544 2545 2546

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

    /* I need to parse the textual return in order to get the storage pools */
2550
    if (exit_status < 0 || ret == NULL) {
2551
        goto cleanup;
2552
    } else {
2553 2554 2555
        storage_pools = ret;

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

E
Eric Blake 已提交
2558 2559
            if (char_ptr) {
                *char_ptr = '\0';
2560
                if (VIR_STRDUP(pools[got++], storage_pools) < 0)
2561
                    goto cleanup;
E
Eric Blake 已提交
2562 2563
                char_ptr++;
                storage_pools = char_ptr;
2564
            } else {
2565
                break;
2566
            }
2567 2568 2569
        }
    }

2570 2571
    success = true;

2572
 cleanup:
2573 2574 2575 2576 2577 2578
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(pools[i]);

        got = -1;
    }
2579
    VIR_FREE(ret);
2580
    return got;
2581 2582 2583
}

static virStoragePoolPtr
2584 2585
phypStoragePoolLookupByUUID(virConnectPtr conn,
                            const unsigned char *uuid)
2586 2587 2588 2589 2590
{
    virStoragePoolPtr sp = NULL;
    int npools = 0;
    int gotpools = 0;
    char **pools = NULL;
2591
    size_t i = 0;
2592 2593
    unsigned char *local_uuid = NULL;

2594
    if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0)
2595 2596
        goto err;

2597
    if ((npools = phypConnectNumOfStoragePools(conn)) == -1)
2598 2599
        goto err;

2600
    if (VIR_ALLOC_N(pools, npools) < 0)
2601 2602
        goto err;

2603
    if ((gotpools = phypConnectListStoragePools(conn, pools, npools)) == -1)
2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
        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)) {
2616
            sp = virGetStoragePool(conn, pools[i], uuid, NULL, NULL);
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626
            VIR_FREE(local_uuid);
            VIR_FREE(pools);

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

2627
 err:
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
    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;
2640
    virStoragePoolPtr dup_sp = NULL;
2641 2642 2643 2644 2645 2646
    virStoragePoolPtr sp = NULL;

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

    /* checking if this name already exists on this system */
2647
    if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) {
2648
        VIR_WARN("StoragePool name already exists.");
2649
        virObjectUnref(dup_sp);
2650 2651 2652 2653
        goto err;
    }

    /* checking if ID or UUID already exists on this system */
2654
    if ((dup_sp = phypStoragePoolLookupByUUID(conn, def->uuid)) != NULL) {
2655
        VIR_WARN("StoragePool uuid already exists.");
2656
        virObjectUnref(dup_sp);
2657 2658
        goto err;
    }
2659

2660
    if ((sp = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL)) == NULL)
2661 2662 2663 2664 2665 2666 2667
        goto err;

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

    return sp;

2668
 err:
2669
    virStoragePoolDefFree(def);
2670
    virObjectUnref(sp);
2671 2672 2673 2674
    return NULL;
}

static char *
2675
phypStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
2676 2677 2678 2679 2680 2681
{
    virCheckFlags(0, NULL);

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

2682
    if (pool->name != NULL) {
2683
        def.name = pool->name;
2684
    } else {
2685
        VIR_ERROR(_("Unable to determine storage pool's name."));
2686 2687 2688
        goto err;
    }

2689
    if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2690
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2691 2692 2693 2694 2695
        goto err;
    }

    if ((def.capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2696
        VIR_ERROR(_("Unable to determine storage pools's size."));
2697 2698 2699
        goto err;
    }

J
Ján Tomko 已提交
2700
    /* Information not available */
2701 2702 2703 2704 2705 2706
    def.allocation = 0;
    def.available = 0;

    def.source.ndevice = 1;

    /*XXX source adapter not working properly, should show hdiskX */
2707
    if ((def.source.adapter.data.scsi_host.name =
2708
         phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
2709
        VIR_ERROR(_("Unable to determine storage pools's source adapter."));
2710 2711 2712 2713 2714
        goto err;
    }

    return virStoragePoolDefFormat(&def);

2715
 err:
2716
    return NULL;
2717 2718
}

E
Eduardo Otubo 已提交
2719 2720 2721 2722 2723 2724 2725
static int
phypInterfaceDestroy(virInterfacePtr iface,
                     unsigned int flags)
{
    virCheckFlags(0, -1);

    phyp_driverPtr phyp_driver = iface->conn->privateData;
2726
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
2727 2728 2729 2730 2731 2732 2733
    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 已提交
2734
    int rv = -1;
E
Eduardo Otubo 已提交
2735 2736 2737 2738 2739

    /* Getting the remote slot number */

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

2742
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2743 2744 2745
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,slot_num|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2746
    if (phypExecInt(session, &buf, iface->conn, &slot_num) < 0)
E
Eric Blake 已提交
2747
        goto cleanup;
E
Eduardo Otubo 已提交
2748 2749 2750 2751

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

2754
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2755 2756 2757
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,lpar_id|"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2758
    if (phypExecInt(session, &buf, iface->conn, &lpar_id) < 0)
E
Eric Blake 已提交
2759
        goto cleanup;
E
Eduardo Otubo 已提交
2760 2761 2762 2763

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

2766
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2767 2768
                      " -r virtualio --rsubtype eth"
                      " --id %d -o r -s %d", lpar_id, slot_num);
2769 2770
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, iface->conn, false);
E
Eduardo Otubo 已提交
2771 2772

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

E
Eric Blake 已提交
2775
    rv = 0;
E
Eduardo Otubo 已提交
2776

2777
 cleanup:
E
Eduardo Otubo 已提交
2778
    VIR_FREE(ret);
E
Eric Blake 已提交
2779
    return rv;
E
Eduardo Otubo 已提交
2780 2781 2782 2783 2784 2785 2786 2787 2788
}

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

    phyp_driverPtr phyp_driver = conn->privateData;
2789
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
2790 2791 2792 2793 2794 2795 2796 2797 2798
    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 已提交
2799
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2800 2801

    if (!(def = virInterfaceDefParseString(xml)))
E
Eric Blake 已提交
2802
        goto cleanup;
E
Eduardo Otubo 已提交
2803 2804 2805 2806

    /* Now need to get the next free slot number */
    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"
                      " -Fslot_num --filter lpar_names=%s"
                      " |sort|tail -n 1", def->name);
E
Eric Blake 已提交
2813
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2814
        goto cleanup;
E
Eduardo Otubo 已提交
2815 2816 2817 2818 2819 2820 2821

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

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

2824
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2825 2826 2827
                      " -r virtualio --rsubtype eth"
                      " -p %s -o a -s %d -a port_vlan_id=1,"
                      "ieee_virtual_eth=0", def->name, slot);
2828 2829
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2830 2831

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2832
        goto cleanup;
E
Eduardo Otubo 已提交
2833 2834 2835 2836 2837 2838 2839 2840 2841

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

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

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

2857
        virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2858 2859
                " -r virtualio --rsubtype eth"
                " -p %s -o r -s %d", def->name, slot);
2860 2861
        VIR_FREE(ret);
        ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eric Blake 已提交
2862
        goto cleanup;
E
Eduardo Otubo 已提交
2863 2864 2865 2866 2867 2868 2869
    }

    memcpy(name, ret, PHYP_IFACENAME_SIZE-1);

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

2872
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2873 2874 2875
                      "-r virtualio --rsubtype eth --level lpar "
                      " |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
                      "s/^.*mac_addr=//'", def->name, slot);
2876 2877
    VIR_FREE(ret);
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2878 2879

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2880
        goto cleanup;
E
Eduardo Otubo 已提交
2881 2882 2883

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2886
 cleanup:
E
Eduardo Otubo 已提交
2887 2888
    VIR_FREE(ret);
    virInterfaceDefFree(def);
E
Eric Blake 已提交
2889
    return result;
E
Eduardo Otubo 已提交
2890 2891 2892 2893 2894 2895
}

static virInterfacePtr
phypInterfaceLookupByName(virConnectPtr conn, const char *name)
{
    phyp_driverPtr phyp_driver = conn->privateData;
2896
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
2897 2898 2899 2900 2901 2902 2903 2904
    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];
2905
    virInterfacePtr result = NULL;
E
Eduardo Otubo 已提交
2906 2907 2908 2909

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

2912
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2913 2914 2915
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,slot_num |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
2916
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2917
        goto cleanup;
E
Eduardo Otubo 已提交
2918 2919 2920 2921

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

2924
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2925 2926 2927
                      " -r virtualio --rsubtype slot --level slot "
                      " -F drc_name,lpar_id |"
                      " sed -n '/%s/ s/^.*,//p'", name);
E
Eric Blake 已提交
2928
    if (phypExecInt(session, &buf, conn, &lpar_id) < 0)
E
Eric Blake 已提交
2929
        goto cleanup;
E
Eduardo Otubo 已提交
2930 2931 2932 2933

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

2936
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2937 2938 2939
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F lpar_id,slot_num,mac_addr|"
                      " sed -n '/%d,%d/ s/^.*,//p'", lpar_id, slot);
2940
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
E
Eduardo Otubo 已提交
2941 2942

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2943
        goto cleanup;
E
Eduardo Otubo 已提交
2944 2945 2946

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2949
 cleanup:
E
Eduardo Otubo 已提交
2950 2951 2952 2953 2954 2955 2956 2957
    VIR_FREE(ret);
    return result;
}

static int
phypInterfaceIsActive(virInterfacePtr iface)
{
    phyp_driverPtr phyp_driver = iface->conn->privateData;
2958
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
2959 2960 2961
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
E
Eric Blake 已提交
2962
    int state = -1;
E
Eduardo Otubo 已提交
2963 2964 2965

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

2968
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2969 2970 2971
                      " -r virtualio --rsubtype eth --level lpar "
                      " -F mac_addr,state |"
                      " sed -n '/%s/ s/^.*,//p'", iface->mac);
E
Eric Blake 已提交
2972
    phypExecInt(session, &buf, iface->conn, &state);
E
Eduardo Otubo 已提交
2973 2974 2975 2976
    return state;
}

static int
2977
phypConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
E
Eduardo Otubo 已提交
2978 2979
{
    phyp_driverPtr phyp_driver = conn->privateData;
2980
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
2981 2982 2983 2984 2985
    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;
2986
    size_t i;
E
Eduardo Otubo 已提交
2987 2988
    char *ret = NULL;
    char *networks = NULL;
E
Eric Blake 已提交
2989
    char *char_ptr = NULL;
E
Eduardo Otubo 已提交
2990
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
2991
    bool success = false;
E
Eduardo Otubo 已提交
2992 2993 2994

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

E
Eric Blake 已提交
3001 3002
    /* I need to parse the textual return in order to get the network
     * interfaces */
E
Eduardo Otubo 已提交
3003
    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
3004
        goto cleanup;
E
Eduardo Otubo 已提交
3005 3006 3007 3008

    networks = ret;

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

E
Eric Blake 已提交
3011 3012
        if (char_ptr) {
            *char_ptr = '\0';
3013
            if (VIR_STRDUP(names[got++], networks) < 0)
E
Eric Blake 已提交
3014
                goto cleanup;
E
Eric Blake 已提交
3015 3016
            char_ptr++;
            networks = char_ptr;
E
Eduardo Otubo 已提交
3017 3018 3019 3020 3021
        } else {
            break;
        }
    }

3022
 cleanup:
E
Eric Blake 已提交
3023 3024 3025 3026
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);
    }
E
Eduardo Otubo 已提交
3027 3028 3029 3030 3031
    VIR_FREE(ret);
    return got;
}

static int
3032
phypConnectNumOfInterfaces(virConnectPtr conn)
E
Eduardo Otubo 已提交
3033 3034
{
    phyp_driverPtr phyp_driver = conn->privateData;
3035
    LIBSSH2_SESSION *session = phyp_driver->session;
E
Eduardo Otubo 已提交
3036 3037 3038
    char *managed_system = phyp_driver->managed_system;
    int system_type = phyp_driver->system_type;
    int vios_id = phyp_driver->vios_id;
E
Eric Blake 已提交
3039
    int nnets = -1;
E
Eduardo Otubo 已提交
3040 3041 3042 3043
    virBuffer buf = VIR_BUFFER_INITIALIZER;

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

3046
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
3047 3048
                      "-r virtualio --rsubtype eth --level lpar|"
                      "grep -v lpar_id=%d|grep -c lpar_name", vios_id);
E
Eric Blake 已提交
3049
    phypExecInt(session, &buf, conn, &nnets);
E
Eduardo Otubo 已提交
3050 3051 3052
    return nnets;
}

3053 3054
static int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
3055 3056
{
    phyp_driverPtr phyp_driver = conn->privateData;
3057
    LIBSSH2_SESSION *session = phyp_driver->session;
3058 3059 3060 3061 3062 3063
    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;
3064

3065 3066
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3067 3068
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -F state --filter lpar_ids=%d", lpar_id);
3069
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3070

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

3074 3075 3076 3077 3078 3079
    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;
3080

3081
 cleanup:
3082 3083
    VIR_FREE(ret);
    return state;
3084 3085
}

3086 3087 3088 3089
/* XXX - is this needed? */
static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED;
static int
phypDiskType(virConnectPtr conn, char *backing_device)
3090 3091
{
    phyp_driverPtr phyp_driver = conn->privateData;
3092
    LIBSSH2_SESSION *session = phyp_driver->session;
3093 3094 3095 3096 3097 3098 3099
    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;
3100

3101 3102
    virBufferAddLit(&buf, "viosvrcmd");
    if (system_type == HMC)
3103 3104
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -p %d -c \"lssp -field name type "
E
Eric Blake 已提交
3105
                      "-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"",
3106
                      vios_id, backing_device);
3107
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
3108

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

3112
    if (STREQ(ret, "LVPOOL"))
E
Eric Blake 已提交
3113
        disk_type = VIR_STORAGE_TYPE_BLOCK;
3114
    else if (STREQ(ret, "FBPOOL"))
E
Eric Blake 已提交
3115
        disk_type = VIR_STORAGE_TYPE_FILE;
3116

3117
 cleanup:
3118 3119 3120
    VIR_FREE(ret);
    return disk_type;
}
3121

3122
static int
3123
phypConnectNumOfDefinedDomains(virConnectPtr conn)
3124
{
3125
    return phypConnectNumOfDomainsGeneric(conn, 1);
3126
}
3127

3128
static int
3129
phypConnectNumOfDomains(virConnectPtr conn)
3130
{
3131
    return phypConnectNumOfDomainsGeneric(conn, 0);
3132 3133
}

3134
static int
3135
phypConnectListDomains(virConnectPtr conn, int *ids, int nids)
3136
{
3137
    return phypConnectListDomainsGeneric(conn, ids, nids, 0);
3138
}
3139

3140
static int
3141
phypConnectListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
3142
{
3143
    bool success = false;
3144
    phyp_driverPtr phyp_driver = conn->privateData;
3145
    LIBSSH2_SESSION *session = phyp_driver->session;
3146 3147 3148 3149
    int system_type = phyp_driver->system_type;
    char *managed_system = phyp_driver->managed_system;
    int exit_status = 0;
    int got = 0;
3150
    size_t i;
3151 3152
    char *ret = NULL;
    char *domains = NULL;
E
Eric Blake 已提交
3153
    char *char_ptr = NULL;
3154
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3155

3156 3157
    virBufferAddLit(&buf, "lssyscfg -r lpar");
    if (system_type == HMC)
3158
        virBufferAsprintf(&buf, " -m %s", managed_system);
3159
    virBufferAddLit(&buf, " -F name,state"
E
Eric Blake 已提交
3160
                      "|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'");
3161
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3162

3163
    /* I need to parse the textual return in order to get the domains */
3164
    if (exit_status < 0 || ret == NULL) {
3165
        goto cleanup;
3166
    } else {
3167
        domains = ret;
3168

3169
        while (got < nnames) {
E
Eric Blake 已提交
3170
            char_ptr = strchr(domains, '\n');
3171

E
Eric Blake 已提交
3172 3173
            if (char_ptr) {
                *char_ptr = '\0';
3174
                if (VIR_STRDUP(names[got++], domains) < 0)
3175
                    goto cleanup;
E
Eric Blake 已提交
3176 3177
                char_ptr++;
                domains = char_ptr;
3178
            } else {
3179
                break;
3180
            }
3181
        }
3182 3183
    }

3184 3185
    success = true;

3186
 cleanup:
3187 3188 3189 3190 3191 3192
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);

        got = -1;
    }
3193
    VIR_FREE(ret);
3194
    return got;
3195 3196
}

3197 3198
static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
3199
{
3200
    phyp_driverPtr phyp_driver = conn->privateData;
3201
    LIBSSH2_SESSION *session = phyp_driver->session;
3202 3203 3204 3205
    virDomainPtr dom = NULL;
    int lpar_id = 0;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];
3206

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

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

3214 3215 3216 3217 3218 3219
    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
3220 3221
}

3222 3223
static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
3224
{
3225
    phyp_driverPtr phyp_driver = conn->privateData;
3226
    LIBSSH2_SESSION *session = phyp_driver->session;
3227 3228 3229
    virDomainPtr dom = NULL;
    char *managed_system = phyp_driver->managed_system;
    unsigned char lpar_uuid[VIR_UUID_BUFLEN];
E
Eduardo Otubo 已提交
3230

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

3234
    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
3235
        goto cleanup;
3236

3237
    dom = virGetDomain(conn, lpar_name, lpar_uuid);
3238

3239 3240
    if (dom)
        dom->id = lpar_id;
3241

3242
 cleanup:
3243
    VIR_FREE(lpar_name);
3244

3245
    return dom;
3246 3247
}

3248
static char *
3249
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3250
{
3251
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3252
    LIBSSH2_SESSION *session = phyp_driver->session;
3253 3254
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;
E
Eduardo Otubo 已提交
3255

3256 3257
    /* Flags checked by virDomainDefFormat */

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

3260 3261 3262 3263 3264 3265 3266
    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) {
3267
        VIR_ERROR(_("Unable to determine domain's name."));
3268
        goto err;
E
Eduardo Otubo 已提交
3269 3270
    }

3271
    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
3272
        VIR_ERROR(_("Unable to generate random uuid."));
E
Eduardo Otubo 已提交
3273 3274
        goto err;
    }
3275

3276
    if ((def.mem.max_balloon =
3277
         phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
3278
        VIR_ERROR(_("Unable to determine domain's max memory."));
3279 3280
        goto err;
    }
3281

3282
    if ((def.mem.cur_balloon =
3283
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
3284
        VIR_ERROR(_("Unable to determine domain's memory."));
3285 3286
        goto err;
    }
3287

E
Eric Blake 已提交
3288
    if ((def.maxvcpus = def.vcpus =
3289
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
3290
        VIR_ERROR(_("Unable to determine domain's CPU."));
3291
        goto err;
3292
    }
3293

3294 3295
    return virDomainDefFormat(&def,
                              virDomainDefFormatConvertXMLFlags(flags));
3296

3297
 err:
3298 3299
    return NULL;
}
3300

3301 3302 3303
static int
phypDomainResume(virDomainPtr dom)
{
3304
    int result = -1;
3305
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3306
    LIBSSH2_SESSION *session = phyp_driver->session;
3307 3308 3309 3310 3311
    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;
3312

3313 3314
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3315 3316
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
3317
                      dom->id, dom->name);
3318
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3319

3320
    if (exit_status < 0)
3321
        goto cleanup;
3322

3323
    result = 0;
3324

3325
 cleanup:
3326
    VIR_FREE(ret);
3327 3328

    return result;
3329 3330
}

3331
static int
E
Eric Blake 已提交
3332
phypDomainReboot(virDomainPtr dom, unsigned int flags)
3333 3334 3335 3336
{
    int result = -1;
    virConnectPtr conn = dom->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
3337
    LIBSSH2_SESSION *session = phyp_driver->session;
3338 3339 3340 3341 3342 3343
    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 已提交
3344 3345
    virCheckFlags(0, -1);

3346 3347
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3348 3349
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
3350 3351 3352 3353 3354 3355 3356 3357 3358
                      " -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;

3359
 cleanup:
3360 3361 3362 3363 3364
    VIR_FREE(ret);

    return result;
}

3365 3366
static int
phypDomainShutdown(virDomainPtr dom)
3367
{
3368
    int result = -1;
3369 3370
    virConnectPtr conn = dom->conn;
    phyp_driverPtr phyp_driver = conn->privateData;
3371
    LIBSSH2_SESSION *session = phyp_driver->session;
3372 3373 3374 3375 3376 3377 3378 3379
    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)
3380 3381
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o shutdown --id %d", dom->id);
3382
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3383 3384

    if (exit_status < 0)
3385
        goto cleanup;
3386

3387
    result = 0;
3388

3389
 cleanup:
3390
    VIR_FREE(ret);
3391 3392

    return result;
3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404
}

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)
3405
        VIR_WARN("Unable to determine domain's max memory.");
3406 3407 3408

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

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

    return 0;
}

3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432
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;
}

3433
static int
3434 3435
phypDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
3436
{
3437
    int result = -1;
3438
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3439
    LIBSSH2_SESSION *session = phyp_driver->session;
3440 3441 3442 3443 3444 3445
    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;

3446 3447
    virCheckFlags(0, -1);

3448 3449
    virBufferAddLit(&buf, "rmsyscfg");
    if (system_type == HMC)
3450 3451
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
3452
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3453 3454

    if (exit_status < 0)
3455
        goto cleanup;
3456 3457

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
3458
        goto cleanup;
3459

3460
    dom->id = -1;
3461
    result = 0;
3462

3463
 cleanup:
3464 3465
    VIR_FREE(ret);

3466
    return result;
3467
}
3468

3469 3470 3471 3472 3473 3474
static int
phypDomainDestroy(virDomainPtr dom)
{
    return phypDomainDestroyFlags(dom, 0);
}

3475 3476
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
3477
{
3478
    int result = -1;
3479
    phyp_driverPtr phyp_driver = conn->privateData;
3480
    LIBSSH2_SESSION *session = phyp_driver->session;
3481 3482 3483 3484 3485
    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;
3486

3487
    if (!def->mem.cur_balloon) {
3488 3489 3490
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <memory> on the domain XML file is missing or has "
                         "invalid value."));
3491
        goto cleanup;
3492 3493
    }

3494
    if (!def->mem.max_balloon) {
3495 3496 3497
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <currentMemory> on the domain XML file is missing or "
                         "has invalid value."));
3498
        goto cleanup;
3499 3500
    }

3501
    if (def->ndisks < 1) {
3502 3503
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain XML must contain at least one <disk> element."));
3504
        goto cleanup;
3505 3506
    }

3507
    if (!virDomainDiskGetSource(def->disks[0])) {
3508 3509 3510
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <src> under <disk> on the domain XML file is "
                         "missing."));
3511
        goto cleanup;
3512 3513
    }

3514 3515
    virBufferAddLit(&buf, "mksyscfg");
    if (system_type == HMC)
3516
        virBufferAsprintf(&buf, " -m %s", managed_system);
3517 3518 3519 3520
    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,
3521
                      (int) def->vcpus, virDomainDiskGetSource(def->disks[0]));
3522
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3523

3524
    if (exit_status < 0) {
3525
        VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
3526
        goto cleanup;
3527
    }
3528

3529
    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
3530
        VIR_ERROR(_("Unable to add LPAR to the table"));
3531
        goto cleanup;
3532
    }
3533

3534
    result = 0;
3535

3536
 cleanup:
3537
    VIR_FREE(ret);
3538 3539

    return result;
3540
}
3541

3542
static virDomainPtr
3543 3544
phypDomainCreateXML(virConnectPtr conn,
                    const char *xml, unsigned int flags)
3545
{
E
Eduardo Otubo 已提交
3546
    virCheckFlags(0, NULL);
3547

3548 3549
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
3550 3551 3552 3553
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
3554
    size_t i = 0;
3555
    char *managed_system = phyp_driver->managed_system;
3556
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
3557

3558 3559 3560 3561
    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
3562

3563 3564 3565
    if (!(def = virDomainDefParseString(xml, phyp_driver->caps,
                                        phyp_driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_PHYP,
3566
                                        parse_flags)))
3567 3568 3569
        goto err;

    /* checking if this name already exists on this system */
3570
    if (phypGetLparID(session, managed_system, def->name, conn) != -1) {
3571
        VIR_WARN("LPAR name already exists.");
3572 3573 3574 3575 3576 3577
        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) {
3578
            VIR_WARN("LPAR ID or UUID already exists.");
3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593
            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;

3594
 err:
3595
    virDomainDefFree(def);
3596
    virObjectUnref(dom);
3597 3598 3599 3600 3601 3602 3603 3604
    return NULL;
}

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

3605
    return virCapabilitiesFormatXML(phyp_driver->caps);
3606 3607 3608
}

static int
3609 3610
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3611 3612
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3613
    LIBSSH2_SESSION *session = phyp_driver->session;
3614 3615 3616 3617 3618 3619 3620 3621 3622
    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;

3623
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
3624
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
3625 3626 3627
        return -1;
    }

3628 3629 3630
    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        return 0;

3631
    if (nvcpus > phypDomainGetMaxVcpus(dom)) {
3632
        VIR_ERROR(_("You are trying to set a number of CPUs bigger than "
3633 3634 3635 3636 3637 3638 3639 3640 3641 3642
                     "the max possible."));
        return 0;
    }

    if (ncpus > nvcpus) {
        operation = 'r';
        amount = nvcpus - ncpus;
    } else if (ncpus < nvcpus) {
        operation = 'a';
        amount = nvcpus - ncpus;
3643
    } else {
3644
        return 0;
3645
    }
3646 3647 3648

    virBufferAddLit(&buf, "chhwres -r proc");
    if (system_type == HMC)
3649 3650
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --id %d -o %c --procunits %d 2>&1 |sed "
3651 3652
                      "-e 's/^.*\\([0-9][0-9]*.[0-9][0-9]*\\).*$/\\1/'",
                      dom->id, operation, amount);
3653
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3654 3655

    if (exit_status < 0) {
3656
        VIR_ERROR(_
3657 3658 3659 3660 3661 3662
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    " Contact your support to enable this feature."));
    }

    VIR_FREE(ret);
    return 0;
3663 3664

}
3665

3666
static int
3667
phypDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3668 3669 3670 3671
{
    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697
static int
phypDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{

    phyp_driverPtr phyp_driver = dom->conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
    char *managed_system = phyp_driver->managed_system;
    char *lpar_name = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

    lpar_name = phypGetLparNAME(session, managed_system, dom->id, dom->conn);

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

    ret = 0;

 cleanup:
    VIR_FREE(lpar_name);
    return ret;
}

3698
static virHypervisorDriver phypHypervisorDriver = {
3699
    .name = "PHYP",
3700 3701
    .connectOpen = phypConnectOpen, /* 0.7.0 */
    .connectClose = phypConnectClose, /* 0.7.0 */
3702
    .connectGetCapabilities = phypConnectGetCapabilities, /* 0.7.3 */
3703 3704 3705
    .connectListDomains = phypConnectListDomains, /* 0.7.0 */
    .connectNumOfDomains = phypConnectNumOfDomains, /* 0.7.0 */
    .domainCreateXML = phypDomainCreateXML, /* 0.7.3 */
3706 3707 3708 3709 3710 3711
    .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 */
3712
    .domainDestroyFlags = phypDomainDestroyFlags, /* 0.9.4 */
3713 3714
    .domainGetInfo = phypDomainGetInfo, /* 0.7.0 */
    .domainGetState = phypDomainGetState, /* 0.9.2 */
3715
    .domainSetVcpus = phypDomainSetVcpus, /* 0.7.3 */
3716 3717
    .domainSetVcpusFlags = phypDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = phypDomainGetVcpusFlags, /* 0.8.5 */
3718
    .domainGetMaxVcpus = phypDomainGetMaxVcpus, /* 0.7.3 */
3719
    .domainGetXMLDesc = phypDomainGetXMLDesc, /* 0.7.0 */
3720 3721 3722 3723 3724 3725 3726
    .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 */
3727
    .domainHasManagedSaveImage = phypDomainHasManagedSaveImage, /* 1.2.13 */
3728 3729
};

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

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

E
Eduardo Otubo 已提交
3748
static virInterfaceDriver phypInterfaceDriver = {
3749 3750
    .connectNumOfInterfaces = phypConnectNumOfInterfaces, /* 0.9.1 */
    .connectListInterfaces = phypConnectListInterfaces, /* 0.9.1 */
3751 3752 3753 3754
    .interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
    .interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
    .interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
    .interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
3755 3756
};

3757 3758 3759 3760 3761 3762
static virConnectDriver phypConnectDriver = {
    .hypervisorDriver = &phypHypervisorDriver,
    .interfaceDriver = &phypInterfaceDriver,
    .storageDriver = &phypStorageDriver,
};

3763 3764 3765
int
phypRegister(void)
{
3766 3767
    return virRegisterConnectDriver(&phypConnectDriver,
                                    false);
3768
}