phyp_driver.c 106.5 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

static int
1097
phypDomainDefPostParse(virDomainDefPtr def,
1098 1099 1100
                       virCapsPtr caps ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
{
1101 1102 1103 1104
    /* memory hotplug tunables are not supported by this driver */
    if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0)
        return -1;

1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    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,
};


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

E
Eric Blake 已提交
1136 1137
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

1150
    if (VIR_ALLOC(phyp_driver) < 0)
1151
        goto failure;
1152

1153
    phyp_driver->sock = -1;
1154

1155
    if (VIR_ALLOC(uuid_table) < 0)
1156
        goto failure;
1157

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

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

    if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
1181 1182
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Error while opening SSH session."));
1183 1184 1185
        goto failure;
    }

1186 1187
    phyp_driver->session = session;
    phyp_driver->sock = internal_socket;
1188 1189 1190 1191 1192 1193 1194 1195

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

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

    phyp_driver->uuid_table = uuid_table;
1196
    if ((phyp_driver->caps = phypCapsInit()) == NULL)
1197
        goto failure;
1198

1199 1200
    if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig,
                                                      NULL, NULL)))
1201 1202
        goto failure;

1203
    conn->privateData = phyp_driver;
1204

1205 1206
    if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
        goto failure;
1207

1208 1209
    if (phypUUIDTable_Init(conn) == -1)
        goto failure;
1210

1211 1212 1213 1214 1215 1216 1217
    if (phyp_driver->system_type == HMC) {
        if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
            goto failure;
    }

    return VIR_DRV_OPEN_SUCCESS;

1218
 failure:
1219 1220
    VIR_FREE(managed_system);

1221
    if (phyp_driver != NULL) {
1222
        virObjectUnref(phyp_driver->caps);
1223
        virObjectUnref(phyp_driver->xmlopt);
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
        VIR_FREE(phyp_driver);
    }

    phypUUIDTable_Free(uuid_table);

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

1234
    VIR_FORCE_CLOSE(internal_socket);
1235 1236

    return VIR_DRV_OPEN_ERROR;
1237 1238 1239
}

static int
1240
phypConnectClose(virConnectPtr conn)
1241
{
1242
    phyp_driverPtr phyp_driver = conn->privateData;
1243
    LIBSSH2_SESSION *session = phyp_driver->session;
1244

1245 1246
    libssh2_session_disconnect(session, "Disconnecting...");
    libssh2_session_free(session);
1247

1248
    virObjectUnref(phyp_driver->caps);
1249
    virObjectUnref(phyp_driver->xmlopt);
1250 1251 1252
    phypUUIDTable_Free(phyp_driver->uuid_table);
    VIR_FREE(phyp_driver->managed_system);
    VIR_FREE(phyp_driver);
1253

1254
    VIR_FORCE_CLOSE(phyp_driver->sock);
1255 1256
    return 0;
}
1257 1258


1259
static int
1260
phypConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1261 1262 1263 1264
{
    /* Phyp uses an SSH tunnel, so is always encrypted */
    return 1;
}
1265

1266 1267

static int
1268
phypConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1269 1270 1271
{
    /* Phyp uses an SSH tunnel, so is always secure */
    return 1;
1272 1273
}

1274 1275

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


1290
static int
1291
phypDomainIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
1292 1293 1294
{
    return 0;
}
1295 1296

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

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

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

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

1331
    if (exit_status < 0)
1332 1333
        VIR_FREE(ret);
    return ret;
1334 1335
}

1336 1337 1338 1339 1340 1341 1342 1343 1344

/* 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)
1345 1346
{
    phyp_driverPtr phyp_driver = conn->privateData;
1347 1348
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
1349
    size_t i = 0;
1350

1351 1352
    for (i = 0; i < uuid_table->nlpars; i++) {
        if (lpars[i]->id == lpar_id) {
1353
            memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
1354 1355 1356
            return 0;
        }
    }
1357

1358
    return -1;
1359 1360
}

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

1376 1377
    if (type != 1 && type != 0)
        return 0;
1378

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

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

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

1409 1410 1411 1412
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
    return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
1413 1414
}

1415
static int
1416
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
1417 1418 1419
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
    char *managed_system = phyp_driver->managed_system;
1420

1421
    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
1422
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
1423 1424 1425
        return -1;
    }

1426 1427 1428
    return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}

1429
static int
1430
phypDomainGetMaxVcpus(virDomainPtr dom)
1431 1432 1433 1434 1435
{
    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

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

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

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

1472 1473 1474 1475 1476 1477
    if ((remote_slot =
         phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
        return NULL;

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

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

1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
    /* 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
1500
            goto cleanup;
1501

1502
        if (VIR_STRDUP(backing_device, char_ptr) < 0)
1503
            goto cleanup;
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
    } else {
        backing_device = ret;
        ret = NULL;
    }

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

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

1514
 cleanup:
1515
    VIR_FREE(ret);
1516

1517
    return backing_device;
1518 1519 1520 1521 1522 1523
}

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

1539
    if (exit_status < 0)
1540 1541
        VIR_FREE(ret);
    return ret;
1542 1543 1544 1545 1546 1547
}

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

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1557
        VIR_ERROR(_("Unable to get VIOS profile name."));
1558
        return -1;
1559 1560 1561 1562 1563
    }

    virBufferAddLit(&buf, "lssyscfg");

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

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

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

    if (!(profile = phypGetLparProfile(conn, vios_id))) {
1601
        VIR_ERROR(_("Unable to get VIOS profile name."));
1602
        goto cleanup;
1603 1604 1605
    }

    if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
1606
        VIR_ERROR(_("Unable to get free slot number"));
1607
        goto cleanup;
1608 1609 1610 1611 1612 1613 1614
    }

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

    if (exit_status < 0 || ret == NULL)
1622
        goto cleanup;
1623 1624 1625 1626 1627 1628

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

    if (exit_status < 0 || ret == NULL)
1637
        goto cleanup;
1638 1639 1640 1641 1642 1643

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

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

1654
    result = 0;
1655

1656
 cleanup:
1657 1658 1659
    VIR_FREE(profile);
    VIR_FREE(vios_name);
    VIR_FREE(ret);
1660 1661

    return result;
1662 1663 1664 1665 1666 1667
}

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

1680
    virBufferAddLit(&buf, "lsmap -all -field svsa backing -fmt , ");
1681 1682 1683 1684

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

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

1688
    if (exit_status < 0)
1689 1690
        VIR_FREE(ret);
    return ret;
1691 1692 1693 1694
}


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

1715
    if (!(def = virDomainDefNew()))
E
Eric Blake 已提交
1716 1717
        goto cleanup;

1718
    domain_name = escape_specialcharacters(domain->name);
1719

1720
    if (domain_name == NULL)
1721
        goto cleanup;
1722

1723
    if (VIR_STRDUP(def->os.type, "aix") < 0)
1724
        goto cleanup;
1725

1726
    dev = virDomainDeviceDefParse(xml, def, phyp_driver->caps, NULL,
1727
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
1728
    if (!dev)
1729
        goto cleanup;
1730 1731 1732 1733

    if (!
        (vios_name =
         phypGetLparNAME(session, managed_system, vios_id, conn))) {
1734
        VIR_ERROR(_("Unable to get VIOS name"));
1735
        goto cleanup;
1736 1737 1738 1739 1740 1741 1742 1743
    }

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

    if (system_type == HMC)
1755
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1756 1757
                          managed_system, vios_id);

1758
    virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
1759
                      virDomainDiskGetSource(dev->data.disk), scsi_adapter);
1760 1761 1762

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1763
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1764 1765

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

    if (!(profile = phypGetLparProfile(conn, domain->id))) {
1769
        VIR_ERROR(_("Unable to get VIOS profile name."));
1770
        goto cleanup;
1771 1772 1773 1774 1775 1776
    }

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

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

    if (exit_status < 0 || ret == NULL)
1798
        goto cleanup;
1799 1800 1801 1802 1803 1804

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

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

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

1833
    result = 0;
1834

1835
 cleanup:
1836
    VIR_FREE(ret);
1837 1838
    virDomainDeviceDefFree(dev);
    virDomainDefFree(def);
1839 1840
    VIR_FREE(vios_name);
    VIR_FREE(scsi_adapter);
1841 1842 1843 1844
    VIR_FREE(profile);
    VIR_FREE(domain_name);

    return result;
1845 1846
}

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

1863
    virBufferAsprintf(&buf, "lslv %s -field lvid", name);
1864 1865 1866 1867

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

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

1871
    if (exit_status < 0)
1872 1873
        VIR_FREE(ret);
    return ret;
1874 1875 1876 1877 1878 1879
}

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

1892
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
1893 1894 1895 1896

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

1897
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
1898
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
1899

1900
    if (exit_status < 0)
1901 1902
        VIR_FREE(ret);
    return ret;
1903 1904 1905 1906 1907 1908
}

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

    if (system_type == HMC)
1917
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1918 1919
                          managed_system, vios_id);

1920
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
1921 1922 1923 1924

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

1925
    virBufferAddLit(&buf, "|sed '1d; s/ //g'");
E
Eric Blake 已提交
1926
    phypExecInt(session, &buf, conn, &sp_size);
1927
    return sp_size;
1928 1929
}

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

    if (system_type == HMC)
1945
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
1946 1947
                          managed_system, vios_id);

1948
    virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
1949 1950 1951

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
1952
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
1953 1954

    if (exit_status < 0) {
1955
        VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
1956
        goto cleanup;
1957 1958
    }

1959
    key = phypStorageVolGetKey(conn, lvname);
1960

1961
 cleanup:
1962 1963
    VIR_FREE(ret);

1964
    return key;
1965 1966 1967
}

static virStorageVolPtr
1968
phypStorageVolLookupByName(virStoragePoolPtr pool, const char *volname)
1969
{
1970 1971
    char *key;
    virStorageVolPtr vol;
1972

1973
    key = phypStorageVolGetKey(pool->conn, volname);
1974

1975
    if (key == NULL)
1976 1977
        return NULL;

1978
    vol = virGetStorageVol(pool->conn, pool->name, volname, key, NULL, NULL);
1979 1980 1981 1982

    VIR_FREE(key);

    return vol;
1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
}

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

    virStorageVolDefPtr voldef = NULL;
    virStoragePoolDefPtr spdef = NULL;
    virStorageVolPtr vol = NULL;
1994
    virStorageVolPtr dup_vol = NULL;
1995 1996
    char *key = NULL;

1997
    if (VIR_ALLOC(spdef) < 0)
1998 1999 2000 2001 2002 2003 2004
        return NULL;

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

    if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2010
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2011 2012 2013 2014 2015
        goto err;
    }

    if ((spdef->capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2016
        VIR_ERROR(_("Unable to determine storage pools's size."));
2017 2018 2019
        goto err;
    }

J
Ján Tomko 已提交
2020
    /* Information not available */
2021 2022 2023 2024 2025 2026
    spdef->allocation = 0;
    spdef->available = 0;

    spdef->source.ndevice = 1;

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

2033
    if ((voldef = virStorageVolDefParseString(spdef, xml, 0)) == NULL) {
2034
        VIR_ERROR(_("Error parsing volume XML."));
2035 2036 2037 2038
        goto err;
    }

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

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

2053
    if (!voldef->target.capacity) {
2054
        VIR_ERROR(_("Capacity cannot be empty."));
2055 2056 2057
        goto err;
    }

2058
    key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
2059
                          voldef->target.capacity);
2060 2061

    if (key == NULL)
2062 2063 2064 2065
        goto err;

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

2069 2070
    VIR_FREE(key);

2071 2072
    return vol;

2073
 err:
2074
    VIR_FREE(key);
2075 2076
    virStorageVolDefFree(voldef);
    virStoragePoolDefFree(spdef);
2077
    virObjectUnref(vol);
2078 2079 2080 2081
    return NULL;
}

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

2098
    virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
2099 2100 2101 2102

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

2103
    virBufferAddLit(&buf, "|sed 1d");
2104
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2105

2106
    if (exit_status < 0)
2107 2108
        VIR_FREE(ret);
    return ret;
2109 2110 2111
}

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

    if (system_type == HMC)
2126
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2127 2128
                          managed_system, vios_id);

2129
    virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
2130 2131 2132 2133

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

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

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

2140
    key = phypStorageVolGetKey(conn, volname);
2141

2142
    if (key == NULL)
2143
        goto cleanup;
2144

2145
    vol = virGetStorageVol(conn, ret, volname, key, NULL, NULL);
2146

2147
 cleanup:
2148
    VIR_FREE(ret);
2149 2150 2151
    VIR_FREE(key);

    return vol;
2152 2153 2154 2155 2156 2157
}

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

2172
    virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
2173 2174 2175 2176

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

2177
    virBufferAddLit(&buf, "|sed '1,2d'");
2178
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2179 2180

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

2183
    if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
2184
        goto cleanup;
2185

2186
    result = 0;
2187

2188
 cleanup:
2189
    VIR_FREE(ret);
2190 2191

    return result;
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201
}

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

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

2202
    return virGetStoragePool(conn, name, uuid, NULL, NULL);
2203 2204 2205
}

static char *
2206
phypStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
2207
{
2208 2209 2210
    virStorageVolDef voldef;
    virStoragePoolDef pool;
    virStoragePoolPtr sp;
2211
    char *xml = NULL;
2212

2213 2214 2215
    virCheckFlags(0, NULL);

    memset(&voldef, 0, sizeof(virStorageVolDef));
2216
    memset(&pool, 0, sizeof(virStoragePoolDef));
2217

2218
    sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
2219 2220

    if (!sp)
2221
        goto cleanup;
2222 2223 2224 2225

    if (sp->name != NULL) {
        pool.name = sp->name;
    } else {
2226
        VIR_ERROR(_("Unable to determine storage sp's name."));
2227
        goto cleanup;
2228 2229
    }

2230
    if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
2231
        VIR_ERROR(_("Unable to determine storage sp's uuid."));
2232
        goto cleanup;
2233 2234 2235
    }

    if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
2236
        VIR_ERROR(_("Unable to determine storage sps's size."));
2237
        goto cleanup;
2238 2239
    }

J
Ján Tomko 已提交
2240
    /* Information not available */
2241 2242 2243 2244 2245
    pool.allocation = 0;
    pool.available = 0;

    pool.source.ndevice = 1;

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

2252
    if (vol->name != NULL) {
2253
        voldef.name = vol->name;
2254
    } else {
2255
        VIR_ERROR(_("Unable to determine storage pool's name."));
2256
        goto cleanup;
2257 2258
    }

2259
    if (VIR_STRDUP(voldef.key, vol->key) < 0)
2260
        goto cleanup;
2261 2262 2263

    voldef.type = VIR_STORAGE_POOL_LOGICAL;

2264 2265 2266 2267
    xml = virStorageVolDefFormat(&pool, &voldef);

    VIR_FREE(voldef.key);

2268
 cleanup:
2269
    virObjectUnref(sp);
2270
    return xml;
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
}

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

    if (system_type == HMC)
2297
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2298 2299
                          managed_system, vios_id);

2300
    virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
2301 2302 2303 2304

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

2305
    virBufferAsprintf(&buf,
2306
                      "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
2307
    ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
2308

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

2312
    pv = phypStorageVolGetPhysicalVolumeByStoragePool(vol, ret);
2313

2314 2315
    if (!pv)
        goto cleanup;
2316

2317
    if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0)
2318
        goto cleanup;
2319

2320
 cleanup:
2321
    VIR_FREE(ret);
2322
    VIR_FREE(path);
2323 2324

    return path;
2325 2326 2327 2328 2329 2330
}

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

    if (system_type == HMC)
2347
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2348 2349
                          managed_system, vios_id);

2350
    virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
2351 2352 2353 2354

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

2355
    virBufferAddLit(&buf, "|sed '1,2d'");
2356
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2357 2358

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

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

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

2379 2380
    success = true;

2381
 cleanup:
2382 2383 2384 2385 2386 2387
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(volumes[i]);

        got = -1;
    }
2388
    VIR_FREE(ret);
2389
    return got;
2390 2391 2392 2393 2394 2395 2396
}

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

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

    /* We need to remove 2 line from the header text output */
E
Eric Blake 已提交
2415
    return nvolumes - 2;
2416 2417 2418
}

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

2436
    virBufferAsprintf(&buf, "rmsp %s", pool->name);
2437 2438 2439

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2440
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2441 2442

    if (exit_status < 0) {
2443
        VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
2444
        goto cleanup;
2445 2446
    }

2447
    result = 0;
2448

2449
 cleanup:
2450
    VIR_FREE(ret);
2451 2452

    return result;
2453 2454 2455 2456 2457
}

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

2469 2470 2471 2472 2473 2474 2475
    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;
    }

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

2480
    virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
2481
                      source.adapter.data.scsi_host.name);
2482 2483 2484

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2485
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2486 2487

    if (exit_status < 0) {
2488
        VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
2489
        goto cleanup;
2490 2491
    }

2492
    result = 0;
2493

2494
 cleanup:
2495
    VIR_FREE(ret);
2496 2497

    return result;
2498 2499 2500 2501

}

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

    if (system_type == HMC)
2513
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2514 2515
                          managed_system, vios_id);

2516
    virBufferAddLit(&buf, "lsvg");
2517 2518 2519 2520

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

2521
    virBufferAddLit(&buf, "|grep -c '^.*$'");
E
Eric Blake 已提交
2522
    phypExecInt(session, &buf, conn, &nsp);
2523
    return nsp;
2524 2525 2526
}

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

    if (system_type == HMC)
2544
        virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
2545 2546
                          managed_system, vios_id);

2547
    virBufferAddLit(&buf, "lsvg");
2548 2549 2550

    if (system_type == HMC)
        virBufferAddChar(&buf, '\'');
2551
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
2552 2553

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

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

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

2574 2575
    success = true;

2576
 cleanup:
2577 2578 2579 2580 2581 2582
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(pools[i]);

        got = -1;
    }
2583
    VIR_FREE(ret);
2584
    return got;
2585 2586 2587
}

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

2598
    if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0)
2599 2600
        goto err;

2601
    if ((npools = phypConnectNumOfStoragePools(conn)) == -1)
2602 2603
        goto err;

2604
    if (VIR_ALLOC_N(pools, npools) < 0)
2605 2606
        goto err;

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

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

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

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

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

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

2664
    if ((sp = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL)) == NULL)
2665 2666 2667 2668 2669 2670 2671
        goto err;

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

    return sp;

2672
 err:
2673
    virStoragePoolDefFree(def);
2674
    virObjectUnref(sp);
2675 2676 2677 2678
    return NULL;
}

static char *
2679
phypStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
2680 2681 2682 2683 2684 2685
{
    virCheckFlags(0, NULL);

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

2686
    if (pool->name != NULL) {
2687
        def.name = pool->name;
2688
    } else {
2689
        VIR_ERROR(_("Unable to determine storage pool's name."));
2690 2691 2692
        goto err;
    }

2693
    if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
2694
        VIR_ERROR(_("Unable to determine storage pool's uuid."));
2695 2696 2697 2698 2699
        goto err;
    }

    if ((def.capacity =
         phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
2700
        VIR_ERROR(_("Unable to determine storage pools's size."));
2701 2702 2703
        goto err;
    }

J
Ján Tomko 已提交
2704
    /* Information not available */
2705 2706 2707 2708 2709 2710
    def.allocation = 0;
    def.available = 0;

    def.source.ndevice = 1;

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

    return virStoragePoolDefFormat(&def);

2719
 err:
2720
    return NULL;
2721 2722
}

E
Eduardo Otubo 已提交
2723 2724 2725 2726 2727 2728 2729
static int
phypInterfaceDestroy(virInterfacePtr iface,
                     unsigned int flags)
{
    virCheckFlags(0, -1);

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

    /* Getting the remote slot number */

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

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

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

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

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

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

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

E
Eric Blake 已提交
2779
    rv = 0;
E
Eduardo Otubo 已提交
2780

2781
 cleanup:
E
Eduardo Otubo 已提交
2782
    VIR_FREE(ret);
E
Eric Blake 已提交
2783
    return rv;
E
Eduardo Otubo 已提交
2784 2785 2786 2787 2788 2789 2790 2791 2792
}

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

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

    if (!(def = virInterfaceDefParseString(xml)))
E
Eric Blake 已提交
2806
        goto cleanup;
E
Eduardo Otubo 已提交
2807 2808 2809 2810

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

2813
    virBufferAsprintf(&buf,
E
Eduardo Otubo 已提交
2814 2815 2816
                      " -r virtualio --rsubtype slot --level slot"
                      " -Fslot_num --filter lpar_names=%s"
                      " |sort|tail -n 1", def->name);
E
Eric Blake 已提交
2817
    if (phypExecInt(session, &buf, conn, &slot) < 0)
E
Eric Blake 已提交
2818
        goto cleanup;
E
Eduardo Otubo 已提交
2819 2820 2821 2822 2823 2824 2825

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

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

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

    if (exit_status < 0 || ret != NULL)
E
Eric Blake 已提交
2836
        goto cleanup;
E
Eduardo Otubo 已提交
2837 2838 2839 2840 2841 2842 2843 2844 2845

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

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

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

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

    memcpy(name, ret, PHYP_IFACENAME_SIZE-1);

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

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

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2884
        goto cleanup;
E
Eduardo Otubo 已提交
2885 2886 2887

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2890
 cleanup:
E
Eduardo Otubo 已提交
2891 2892
    VIR_FREE(ret);
    virInterfaceDefFree(def);
E
Eric Blake 已提交
2893
    return result;
E
Eduardo Otubo 已提交
2894 2895 2896 2897 2898 2899
}

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

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

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

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

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

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

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

    if (exit_status < 0 || ret == NULL)
E
Eric Blake 已提交
2947
        goto cleanup;
E
Eduardo Otubo 已提交
2948 2949 2950

    memcpy(mac, ret, PHYP_MAC_SIZE-1);

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

2953
 cleanup:
E
Eduardo Otubo 已提交
2954 2955 2956 2957 2958 2959 2960 2961
    VIR_FREE(ret);
    return result;
}

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

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

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

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

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

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

    networks = ret;

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

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

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

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

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

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

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

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

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

3078 3079 3080 3081 3082 3083
    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;
3084

3085
 cleanup:
3086 3087
    VIR_FREE(ret);
    return state;
3088 3089
}

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

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

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

3116
    if (STREQ(ret, "LVPOOL"))
E
Eric Blake 已提交
3117
        disk_type = VIR_STORAGE_TYPE_BLOCK;
3118
    else if (STREQ(ret, "FBPOOL"))
E
Eric Blake 已提交
3119
        disk_type = VIR_STORAGE_TYPE_FILE;
3120

3121
 cleanup:
3122 3123 3124
    VIR_FREE(ret);
    return disk_type;
}
3125

3126
static int
3127
phypConnectNumOfDefinedDomains(virConnectPtr conn)
3128
{
3129
    return phypConnectNumOfDomainsGeneric(conn, 1);
3130
}
3131

3132
static int
3133
phypConnectNumOfDomains(virConnectPtr conn)
3134
{
3135
    return phypConnectNumOfDomainsGeneric(conn, 0);
3136 3137
}

3138
static int
3139
phypConnectListDomains(virConnectPtr conn, int *ids, int nids)
3140
{
3141
    return phypConnectListDomainsGeneric(conn, ids, nids, 0);
3142
}
3143

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

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

3167
    /* I need to parse the textual return in order to get the domains */
3168
    if (exit_status < 0 || ret == NULL) {
3169
        goto cleanup;
3170
    } else {
3171
        domains = ret;
3172

3173
        while (got < nnames) {
E
Eric Blake 已提交
3174
            char_ptr = strchr(domains, '\n');
3175

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

3188 3189
    success = true;

3190
 cleanup:
3191 3192 3193 3194 3195 3196
    if (!success) {
        for (i = 0; i < got; i++)
            VIR_FREE(names[i]);

        got = -1;
    }
3197
    VIR_FREE(ret);
3198
    return got;
3199 3200
}

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

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

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

3218 3219 3220 3221 3222 3223
    dom = virGetDomain(conn, lpar_name, lpar_uuid);

    if (dom)
        dom->id = lpar_id;

    return dom;
3224 3225
}

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

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

3238
    if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
3239
        goto cleanup;
3240

3241
    dom = virGetDomain(conn, lpar_name, lpar_uuid);
3242

3243 3244
    if (dom)
        dom->id = lpar_id;
3245

3246
 cleanup:
3247
    VIR_FREE(lpar_name);
3248

3249
    return dom;
3250 3251
}

3252
static char *
3253
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3254
{
3255
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3256
    LIBSSH2_SESSION *session = phyp_driver->session;
3257 3258
    virDomainDef def;
    char *managed_system = phyp_driver->managed_system;
3259
    unsigned long long memory;
E
Eduardo Otubo 已提交
3260

3261 3262
    /* Flags checked by virDomainDefFormat */

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

3265 3266 3267 3268 3269 3270 3271
    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) {
3272
        VIR_ERROR(_("Unable to determine domain's name."));
3273
        goto err;
E
Eduardo Otubo 已提交
3274 3275
    }

3276
    if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
3277
        VIR_ERROR(_("Unable to generate random uuid."));
E
Eduardo Otubo 已提交
3278 3279
        goto err;
    }
3280

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

3286 3287
    virDomainDefSetMemoryInitial(&def, memory);

3288
    if ((def.mem.cur_balloon =
3289
         phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
3290
        VIR_ERROR(_("Unable to determine domain's memory."));
3291 3292
        goto err;
    }
3293

E
Eric Blake 已提交
3294
    if ((def.maxvcpus = def.vcpus =
3295
         phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
3296
        VIR_ERROR(_("Unable to determine domain's CPU."));
3297
        goto err;
3298
    }
3299

3300 3301
    return virDomainDefFormat(&def,
                              virDomainDefFormatConvertXMLFlags(flags));
3302

3303
 err:
3304 3305
    return NULL;
}
3306

3307 3308 3309
static int
phypDomainResume(virDomainPtr dom)
{
3310
    int result = -1;
3311
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3312
    LIBSSH2_SESSION *session = phyp_driver->session;
3313 3314 3315 3316 3317
    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;
3318

3319 3320
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3321 3322
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
3323
                      dom->id, dom->name);
3324
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3325

3326
    if (exit_status < 0)
3327
        goto cleanup;
3328

3329
    result = 0;
3330

3331
 cleanup:
3332
    VIR_FREE(ret);
3333 3334

    return result;
3335 3336
}

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

3352 3353
    virBufferAddLit(&buf, "chsysstate");
    if (system_type == HMC)
3354 3355
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf,
3356 3357 3358 3359 3360 3361 3362 3363 3364
                      " -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;

3365
 cleanup:
3366 3367 3368 3369 3370
    VIR_FREE(ret);

    return result;
}

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

    if (exit_status < 0)
3391
        goto cleanup;
3392

3393
    result = 0;
3394

3395
 cleanup:
3396
    VIR_FREE(ret);
3397 3398

    return result;
3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410
}

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)
3411
        VIR_WARN("Unable to determine domain's max memory.");
3412 3413 3414

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

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

    return 0;
}

3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438
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;
}

3439
static int
3440 3441
phypDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
3442
{
3443
    int result = -1;
3444
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3445
    LIBSSH2_SESSION *session = phyp_driver->session;
3446 3447 3448 3449 3450 3451
    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;

3452 3453
    virCheckFlags(0, -1);

3454 3455
    virBufferAddLit(&buf, "rmsyscfg");
    if (system_type == HMC)
3456 3457
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
3458
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3459 3460

    if (exit_status < 0)
3461
        goto cleanup;
3462 3463

    if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
3464
        goto cleanup;
3465

3466
    dom->id = -1;
3467
    result = 0;
3468

3469
 cleanup:
3470 3471
    VIR_FREE(ret);

3472
    return result;
3473
}
3474

3475 3476 3477 3478 3479 3480
static int
phypDomainDestroy(virDomainPtr dom)
{
    return phypDomainDestroyFlags(dom, 0);
}

3481 3482
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
3483
{
3484
    int result = -1;
3485
    phyp_driverPtr phyp_driver = conn->privateData;
3486
    LIBSSH2_SESSION *session = phyp_driver->session;
3487 3488 3489 3490 3491
    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;
3492

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

3500
    if (!virDomainDefGetMemoryInitial(def)) {
3501
        virReportError(VIR_ERR_XML_ERROR, "%s",
3502 3503
                       _("Field <memory> on the domain XML file is missing or "
                         "has invalid value"));
3504
        goto cleanup;
3505 3506
    }

3507
    if (def->ndisks < 1) {
3508 3509
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain XML must contain at least one <disk> element."));
3510
        goto cleanup;
3511 3512
    }

3513
    if (!virDomainDiskGetSource(def->disks[0])) {
3514 3515 3516
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Field <src> under <disk> on the domain XML file is "
                         "missing."));
3517
        goto cleanup;
3518 3519
    }

3520 3521
    virBufferAddLit(&buf, "mksyscfg");
    if (system_type == HMC)
3522
        virBufferAsprintf(&buf, " -m %s", managed_system);
3523 3524 3525
    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,
3526 3527
                      def->mem.cur_balloon,
                      virDomainDefGetMemoryInitial(def),
3528
                      (int) def->vcpus, virDomainDiskGetSource(def->disks[0]));
3529
    ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
3530

3531
    if (exit_status < 0) {
3532
        VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
3533
        goto cleanup;
3534
    }
3535

3536
    if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
3537
        VIR_ERROR(_("Unable to add LPAR to the table"));
3538
        goto cleanup;
3539
    }
3540

3541
    result = 0;
3542

3543
 cleanup:
3544
    VIR_FREE(ret);
3545 3546

    return result;
3547
}
3548

3549
static virDomainPtr
3550 3551
phypDomainCreateXML(virConnectPtr conn,
                    const char *xml, unsigned int flags)
3552
{
E
Eduardo Otubo 已提交
3553
    virCheckFlags(0, NULL);
3554

3555 3556
    phyp_driverPtr phyp_driver = conn->privateData;
    LIBSSH2_SESSION *session = phyp_driver->session;
3557 3558 3559 3560
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    uuid_tablePtr uuid_table = phyp_driver->uuid_table;
    lparPtr *lpars = uuid_table->lpars;
3561
    size_t i = 0;
3562
    char *managed_system = phyp_driver->managed_system;
3563
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
3564

3565 3566 3567 3568
    virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);

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

3570 3571 3572
    if (!(def = virDomainDefParseString(xml, phyp_driver->caps,
                                        phyp_driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_PHYP,
3573
                                        parse_flags)))
3574 3575 3576
        goto err;

    /* checking if this name already exists on this system */
3577
    if (phypGetLparID(session, managed_system, def->name, conn) != -1) {
3578
        VIR_WARN("LPAR name already exists.");
3579 3580 3581 3582 3583 3584
        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) {
3585
            VIR_WARN("LPAR ID or UUID already exists.");
3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600
            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;

3601
 err:
3602
    virDomainDefFree(def);
3603
    virObjectUnref(dom);
3604 3605 3606 3607 3608 3609 3610 3611
    return NULL;
}

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

3612
    return virCapabilitiesFormatXML(phyp_driver->caps);
3613 3614 3615
}

static int
3616 3617
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3618 3619
{
    phyp_driverPtr phyp_driver = dom->conn->privateData;
3620
    LIBSSH2_SESSION *session = phyp_driver->session;
3621 3622 3623 3624 3625 3626 3627 3628 3629
    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;

3630
    if (flags != VIR_DOMAIN_VCPU_LIVE) {
3631
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
3632 3633 3634
        return -1;
    }

3635 3636 3637
    if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
        return 0;

3638
    if (nvcpus > phypDomainGetMaxVcpus(dom)) {
3639
        VIR_ERROR(_("You are trying to set a number of CPUs bigger than "
3640 3641 3642 3643 3644 3645 3646 3647 3648 3649
                     "the max possible."));
        return 0;
    }

    if (ncpus > nvcpus) {
        operation = 'r';
        amount = nvcpus - ncpus;
    } else if (ncpus < nvcpus) {
        operation = 'a';
        amount = nvcpus - ncpus;
3650
    } else {
3651
        return 0;
3652
    }
3653 3654 3655

    virBufferAddLit(&buf, "chhwres -r proc");
    if (system_type == HMC)
3656 3657
        virBufferAsprintf(&buf, " -m %s", managed_system);
    virBufferAsprintf(&buf, " --id %d -o %c --procunits %d 2>&1 |sed "
3658 3659
                      "-e 's/^.*\\([0-9][0-9]*.[0-9][0-9]*\\).*$/\\1/'",
                      dom->id, operation, amount);
3660
    ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
3661 3662

    if (exit_status < 0) {
3663
        VIR_ERROR(_
3664 3665 3666 3667 3668 3669
                   ("Possibly you don't have IBM Tools installed in your LPAR."
                    " Contact your support to enable this feature."));
    }

    VIR_FREE(ret);
    return 0;
3670 3671

}
3672

3673
static int
3674
phypDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3675 3676 3677 3678
{
    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704
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;
}

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

3737
static virStorageDriver phypStorageDriver = {
3738 3739
    .connectNumOfStoragePools = phypConnectNumOfStoragePools, /* 0.8.2 */
    .connectListStoragePools = phypConnectListStoragePools, /* 0.8.2 */
3740
    .storagePoolLookupByName = phypStoragePoolLookupByName, /* 0.8.2 */
3741
    .storagePoolLookupByUUID = phypStoragePoolLookupByUUID, /* 0.8.2 */
3742
    .storagePoolCreateXML = phypStoragePoolCreateXML, /* 0.8.2 */
3743 3744
    .storagePoolDestroy = phypStoragePoolDestroy, /* 0.8.2 */
    .storagePoolGetXMLDesc = phypStoragePoolGetXMLDesc, /* 0.8.2 */
3745 3746 3747
    .storagePoolNumOfVolumes = phypStoragePoolNumOfVolumes, /* 0.8.2 */
    .storagePoolListVolumes = phypStoragePoolListVolumes, /* 0.8.2 */

3748 3749
    .storageVolLookupByName = phypStorageVolLookupByName, /* 0.8.2 */
    .storageVolLookupByPath = phypStorageVolLookupByPath, /* 0.8.2 */
3750
    .storageVolCreateXML = phypStorageVolCreateXML, /* 0.8.2 */
3751 3752
    .storageVolGetXMLDesc = phypStorageVolGetXMLDesc, /* 0.8.2 */
    .storageVolGetPath = phypStorageVolGetPath, /* 0.8.2 */
3753 3754
};

E
Eduardo Otubo 已提交
3755
static virInterfaceDriver phypInterfaceDriver = {
3756 3757
    .connectNumOfInterfaces = phypConnectNumOfInterfaces, /* 0.9.1 */
    .connectListInterfaces = phypConnectListInterfaces, /* 0.9.1 */
3758 3759 3760 3761
    .interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
    .interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
    .interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
    .interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
3762 3763
};

3764 3765 3766 3767 3768 3769
static virConnectDriver phypConnectDriver = {
    .hypervisorDriver = &phypHypervisorDriver,
    .interfaceDriver = &phypInterfaceDriver,
    .storageDriver = &phypStorageDriver,
};

3770 3771 3772
int
phypRegister(void)
{
3773 3774
    return virRegisterConnectDriver(&phypConnectDriver,
                                    false);
3775
}