qemu/qga/commands-posix.c
<<
>>
Prefs
   1/*
   2 * QEMU Guest Agent POSIX-specific command implementations
   3 *
   4 * Copyright IBM Corp. 2011
   5 *
   6 * Authors:
   7 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
   8 *  Michal Privoznik  <mprivozn@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11 * See the COPYING file in the top-level directory.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include <sys/ioctl.h>
  16#include <sys/utsname.h>
  17#include <sys/wait.h>
  18#include <dirent.h>
  19#include "qga/guest-agent-core.h"
  20#include "qga-qmp-commands.h"
  21#include "qapi/qmp/qerror.h"
  22#include "qemu/queue.h"
  23#include "qemu/host-utils.h"
  24#include "qemu/sockets.h"
  25#include "qemu/base64.h"
  26#include "qemu/cutils.h"
  27
  28#ifdef HAVE_UTMPX
  29#include <utmpx.h>
  30#endif
  31
  32#ifndef CONFIG_HAS_ENVIRON
  33#ifdef __APPLE__
  34#include <crt_externs.h>
  35#define environ (*_NSGetEnviron())
  36#else
  37extern char **environ;
  38#endif
  39#endif
  40
  41#if defined(__linux__)
  42#include <mntent.h>
  43#include <linux/fs.h>
  44#include <ifaddrs.h>
  45#include <arpa/inet.h>
  46#include <sys/socket.h>
  47#include <net/if.h>
  48
  49#ifdef FIFREEZE
  50#define CONFIG_FSFREEZE
  51#endif
  52#ifdef FITRIM
  53#define CONFIG_FSTRIM
  54#endif
  55#endif
  56
  57static void ga_wait_child(pid_t pid, int *status, Error **errp)
  58{
  59    pid_t rpid;
  60
  61    *status = 0;
  62
  63    do {
  64        rpid = waitpid(pid, status, 0);
  65    } while (rpid == -1 && errno == EINTR);
  66
  67    if (rpid == -1) {
  68        error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
  69                         pid);
  70        return;
  71    }
  72
  73    g_assert(rpid == pid);
  74}
  75
  76void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
  77{
  78    const char *shutdown_flag;
  79    Error *local_err = NULL;
  80    pid_t pid;
  81    int status;
  82
  83    slog("guest-shutdown called, mode: %s", mode);
  84    if (!has_mode || strcmp(mode, "powerdown") == 0) {
  85        shutdown_flag = "-P";
  86    } else if (strcmp(mode, "halt") == 0) {
  87        shutdown_flag = "-H";
  88    } else if (strcmp(mode, "reboot") == 0) {
  89        shutdown_flag = "-r";
  90    } else {
  91        error_setg(errp,
  92                   "mode is invalid (valid values are: halt|powerdown|reboot");
  93        return;
  94    }
  95
  96    pid = fork();
  97    if (pid == 0) {
  98        /* child, start the shutdown */
  99        setsid();
 100        reopen_fd_to_null(0);
 101        reopen_fd_to_null(1);
 102        reopen_fd_to_null(2);
 103
 104        execle("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0",
 105               "hypervisor initiated shutdown", (char*)NULL, environ);
 106        _exit(EXIT_FAILURE);
 107    } else if (pid < 0) {
 108        error_setg_errno(errp, errno, "failed to create child process");
 109        return;
 110    }
 111
 112    ga_wait_child(pid, &status, &local_err);
 113    if (local_err) {
 114        error_propagate(errp, local_err);
 115        return;
 116    }
 117
 118    if (!WIFEXITED(status)) {
 119        error_setg(errp, "child process has terminated abnormally");
 120        return;
 121    }
 122
 123    if (WEXITSTATUS(status)) {
 124        error_setg(errp, "child process has failed to shutdown");
 125        return;
 126    }
 127
 128    /* succeeded */
 129}
 130
 131int64_t qmp_guest_get_time(Error **errp)
 132{
 133   int ret;
 134   qemu_timeval tq;
 135
 136   ret = qemu_gettimeofday(&tq);
 137   if (ret < 0) {
 138       error_setg_errno(errp, errno, "Failed to get time");
 139       return -1;
 140   }
 141
 142   return tq.tv_sec * 1000000000LL + tq.tv_usec * 1000;
 143}
 144
 145void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
 146{
 147    int ret;
 148    int status;
 149    pid_t pid;
 150    Error *local_err = NULL;
 151    struct timeval tv;
 152
 153    /* If user has passed a time, validate and set it. */
 154    if (has_time) {
 155        GDate date = { 0, };
 156
 157        /* year-2038 will overflow in case time_t is 32bit */
 158        if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
 159            error_setg(errp, "Time %" PRId64 " is too large", time_ns);
 160            return;
 161        }
 162
 163        tv.tv_sec = time_ns / 1000000000;
 164        tv.tv_usec = (time_ns % 1000000000) / 1000;
 165        g_date_set_time_t(&date, tv.tv_sec);
 166        if (date.year < 1970 || date.year >= 2070) {
 167            error_setg_errno(errp, errno, "Invalid time");
 168            return;
 169        }
 170
 171        ret = settimeofday(&tv, NULL);
 172        if (ret < 0) {
 173            error_setg_errno(errp, errno, "Failed to set time to guest");
 174            return;
 175        }
 176    }
 177
 178    /* Now, if user has passed a time to set and the system time is set, we
 179     * just need to synchronize the hardware clock. However, if no time was
 180     * passed, user is requesting the opposite: set the system time from the
 181     * hardware clock (RTC). */
 182    pid = fork();
 183    if (pid == 0) {
 184        setsid();
 185        reopen_fd_to_null(0);
 186        reopen_fd_to_null(1);
 187        reopen_fd_to_null(2);
 188
 189        /* Use '/sbin/hwclock -w' to set RTC from the system time,
 190         * or '/sbin/hwclock -s' to set the system time from RTC. */
 191        execle("/sbin/hwclock", "hwclock", has_time ? "-w" : "-s",
 192               NULL, environ);
 193        _exit(EXIT_FAILURE);
 194    } else if (pid < 0) {
 195        error_setg_errno(errp, errno, "failed to create child process");
 196        return;
 197    }
 198
 199    ga_wait_child(pid, &status, &local_err);
 200    if (local_err) {
 201        error_propagate(errp, local_err);
 202        return;
 203    }
 204
 205    if (!WIFEXITED(status)) {
 206        error_setg(errp, "child process has terminated abnormally");
 207        return;
 208    }
 209
 210    if (WEXITSTATUS(status)) {
 211        error_setg(errp, "hwclock failed to set hardware clock to system time");
 212        return;
 213    }
 214}
 215
 216typedef enum {
 217    RW_STATE_NEW,
 218    RW_STATE_READING,
 219    RW_STATE_WRITING,
 220} RwState;
 221
 222typedef struct GuestFileHandle {
 223    uint64_t id;
 224    FILE *fh;
 225    RwState state;
 226    QTAILQ_ENTRY(GuestFileHandle) next;
 227} GuestFileHandle;
 228
 229static struct {
 230    QTAILQ_HEAD(, GuestFileHandle) filehandles;
 231} guest_file_state = {
 232    .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
 233};
 234
 235static int64_t guest_file_handle_add(FILE *fh, Error **errp)
 236{
 237    GuestFileHandle *gfh;
 238    int64_t handle;
 239
 240    handle = ga_get_fd_handle(ga_state, errp);
 241    if (handle < 0) {
 242        return -1;
 243    }
 244
 245    gfh = g_new0(GuestFileHandle, 1);
 246    gfh->id = handle;
 247    gfh->fh = fh;
 248    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
 249
 250    return handle;
 251}
 252
 253static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
 254{
 255    GuestFileHandle *gfh;
 256
 257    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
 258    {
 259        if (gfh->id == id) {
 260            return gfh;
 261        }
 262    }
 263
 264    error_setg(errp, "handle '%" PRId64 "' has not been found", id);
 265    return NULL;
 266}
 267
 268typedef const char * const ccpc;
 269
 270#ifndef O_BINARY
 271#define O_BINARY 0
 272#endif
 273
 274/* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
 275static const struct {
 276    ccpc *forms;
 277    int oflag_base;
 278} guest_file_open_modes[] = {
 279    { (ccpc[]){ "r",          NULL }, O_RDONLY                                 },
 280    { (ccpc[]){ "rb",         NULL }, O_RDONLY                      | O_BINARY },
 281    { (ccpc[]){ "w",          NULL }, O_WRONLY | O_CREAT | O_TRUNC             },
 282    { (ccpc[]){ "wb",         NULL }, O_WRONLY | O_CREAT | O_TRUNC  | O_BINARY },
 283    { (ccpc[]){ "a",          NULL }, O_WRONLY | O_CREAT | O_APPEND            },
 284    { (ccpc[]){ "ab",         NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
 285    { (ccpc[]){ "r+",         NULL }, O_RDWR                                   },
 286    { (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR                        | O_BINARY },
 287    { (ccpc[]){ "w+",         NULL }, O_RDWR   | O_CREAT | O_TRUNC             },
 288    { (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR   | O_CREAT | O_TRUNC  | O_BINARY },
 289    { (ccpc[]){ "a+",         NULL }, O_RDWR   | O_CREAT | O_APPEND            },
 290    { (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR   | O_CREAT | O_APPEND | O_BINARY }
 291};
 292
 293static int
 294find_open_flag(const char *mode_str, Error **errp)
 295{
 296    unsigned mode;
 297
 298    for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
 299        ccpc *form;
 300
 301        form = guest_file_open_modes[mode].forms;
 302        while (*form != NULL && strcmp(*form, mode_str) != 0) {
 303            ++form;
 304        }
 305        if (*form != NULL) {
 306            break;
 307        }
 308    }
 309
 310    if (mode == ARRAY_SIZE(guest_file_open_modes)) {
 311        error_setg(errp, "invalid file open mode '%s'", mode_str);
 312        return -1;
 313    }
 314    return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
 315}
 316
 317#define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
 318                               S_IRGRP | S_IWGRP | \
 319                               S_IROTH | S_IWOTH)
 320
 321static FILE *
 322safe_open_or_create(const char *path, const char *mode, Error **errp)
 323{
 324    Error *local_err = NULL;
 325    int oflag;
 326
 327    oflag = find_open_flag(mode, &local_err);
 328    if (local_err == NULL) {
 329        int fd;
 330
 331        /* If the caller wants / allows creation of a new file, we implement it
 332         * with a two step process: open() + (open() / fchmod()).
 333         *
 334         * First we insist on creating the file exclusively as a new file. If
 335         * that succeeds, we're free to set any file-mode bits on it. (The
 336         * motivation is that we want to set those file-mode bits independently
 337         * of the current umask.)
 338         *
 339         * If the exclusive creation fails because the file already exists
 340         * (EEXIST is not possible for any other reason), we just attempt to
 341         * open the file, but in this case we won't be allowed to change the
 342         * file-mode bits on the preexistent file.
 343         *
 344         * The pathname should never disappear between the two open()s in
 345         * practice. If it happens, then someone very likely tried to race us.
 346         * In this case just go ahead and report the ENOENT from the second
 347         * open() to the caller.
 348         *
 349         * If the caller wants to open a preexistent file, then the first
 350         * open() is decisive and its third argument is ignored, and the second
 351         * open() and the fchmod() are never called.
 352         */
 353        fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
 354        if (fd == -1 && errno == EEXIST) {
 355            oflag &= ~(unsigned)O_CREAT;
 356            fd = open(path, oflag);
 357        }
 358
 359        if (fd == -1) {
 360            error_setg_errno(&local_err, errno, "failed to open file '%s' "
 361                             "(mode: '%s')", path, mode);
 362        } else {
 363            qemu_set_cloexec(fd);
 364
 365            if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
 366                error_setg_errno(&local_err, errno, "failed to set permission "
 367                                 "0%03o on new file '%s' (mode: '%s')",
 368                                 (unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
 369            } else {
 370                FILE *f;
 371
 372                f = fdopen(fd, mode);
 373                if (f == NULL) {
 374                    error_setg_errno(&local_err, errno, "failed to associate "
 375                                     "stdio stream with file descriptor %d, "
 376                                     "file '%s' (mode: '%s')", fd, path, mode);
 377                } else {
 378                    return f;
 379                }
 380            }
 381
 382            close(fd);
 383            if (oflag & O_CREAT) {
 384                unlink(path);
 385            }
 386        }
 387    }
 388
 389    error_propagate(errp, local_err);
 390    return NULL;
 391}
 392
 393int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
 394                            Error **errp)
 395{
 396    FILE *fh;
 397    Error *local_err = NULL;
 398    int64_t handle;
 399
 400    if (!has_mode) {
 401        mode = "r";
 402    }
 403    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
 404    fh = safe_open_or_create(path, mode, &local_err);
 405    if (local_err != NULL) {
 406        error_propagate(errp, local_err);
 407        return -1;
 408    }
 409
 410    /* set fd non-blocking to avoid common use cases (like reading from a
 411     * named pipe) from hanging the agent
 412     */
 413    qemu_set_nonblock(fileno(fh));
 414
 415    handle = guest_file_handle_add(fh, errp);
 416    if (handle < 0) {
 417        fclose(fh);
 418        return -1;
 419    }
 420
 421    slog("guest-file-open, handle: %" PRId64, handle);
 422    return handle;
 423}
 424
 425void qmp_guest_file_close(int64_t handle, Error **errp)
 426{
 427    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 428    int ret;
 429
 430    slog("guest-file-close called, handle: %" PRId64, handle);
 431    if (!gfh) {
 432        return;
 433    }
 434
 435    ret = fclose(gfh->fh);
 436    if (ret == EOF) {
 437        error_setg_errno(errp, errno, "failed to close handle");
 438        return;
 439    }
 440
 441    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
 442    g_free(gfh);
 443}
 444
 445struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
 446                                          int64_t count, Error **errp)
 447{
 448    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 449    GuestFileRead *read_data = NULL;
 450    guchar *buf;
 451    FILE *fh;
 452    size_t read_count;
 453
 454    if (!gfh) {
 455        return NULL;
 456    }
 457
 458    if (!has_count) {
 459        count = QGA_READ_COUNT_DEFAULT;
 460    } else if (count < 0) {
 461        error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
 462                   count);
 463        return NULL;
 464    }
 465
 466    fh = gfh->fh;
 467
 468    /* explicitly flush when switching from writing to reading */
 469    if (gfh->state == RW_STATE_WRITING) {
 470        int ret = fflush(fh);
 471        if (ret == EOF) {
 472            error_setg_errno(errp, errno, "failed to flush file");
 473            return NULL;
 474        }
 475        gfh->state = RW_STATE_NEW;
 476    }
 477
 478    buf = g_malloc0(count+1);
 479    read_count = fread(buf, 1, count, fh);
 480    if (ferror(fh)) {
 481        error_setg_errno(errp, errno, "failed to read file");
 482        slog("guest-file-read failed, handle: %" PRId64, handle);
 483    } else {
 484        buf[read_count] = 0;
 485        read_data = g_new0(GuestFileRead, 1);
 486        read_data->count = read_count;
 487        read_data->eof = feof(fh);
 488        if (read_count) {
 489            read_data->buf_b64 = g_base64_encode(buf, read_count);
 490        }
 491        gfh->state = RW_STATE_READING;
 492    }
 493    g_free(buf);
 494    clearerr(fh);
 495
 496    return read_data;
 497}
 498
 499GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
 500                                     bool has_count, int64_t count,
 501                                     Error **errp)
 502{
 503    GuestFileWrite *write_data = NULL;
 504    guchar *buf;
 505    gsize buf_len;
 506    int write_count;
 507    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 508    FILE *fh;
 509
 510    if (!gfh) {
 511        return NULL;
 512    }
 513
 514    fh = gfh->fh;
 515
 516    if (gfh->state == RW_STATE_READING) {
 517        int ret = fseek(fh, 0, SEEK_CUR);
 518        if (ret == -1) {
 519            error_setg_errno(errp, errno, "failed to seek file");
 520            return NULL;
 521        }
 522        gfh->state = RW_STATE_NEW;
 523    }
 524
 525    buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
 526    if (!buf) {
 527        return NULL;
 528    }
 529
 530    if (!has_count) {
 531        count = buf_len;
 532    } else if (count < 0 || count > buf_len) {
 533        error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
 534                   count);
 535        g_free(buf);
 536        return NULL;
 537    }
 538
 539    write_count = fwrite(buf, 1, count, fh);
 540    if (ferror(fh)) {
 541        error_setg_errno(errp, errno, "failed to write to file");
 542        slog("guest-file-write failed, handle: %" PRId64, handle);
 543    } else {
 544        write_data = g_new0(GuestFileWrite, 1);
 545        write_data->count = write_count;
 546        write_data->eof = feof(fh);
 547        gfh->state = RW_STATE_WRITING;
 548    }
 549    g_free(buf);
 550    clearerr(fh);
 551
 552    return write_data;
 553}
 554
 555struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
 556                                          GuestFileWhence *whence_code,
 557                                          Error **errp)
 558{
 559    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 560    GuestFileSeek *seek_data = NULL;
 561    FILE *fh;
 562    int ret;
 563    int whence;
 564    Error *err = NULL;
 565
 566    if (!gfh) {
 567        return NULL;
 568    }
 569
 570    /* We stupidly exposed 'whence':'int' in our qapi */
 571    whence = ga_parse_whence(whence_code, &err);
 572    if (err) {
 573        error_propagate(errp, err);
 574        return NULL;
 575    }
 576
 577    fh = gfh->fh;
 578    ret = fseek(fh, offset, whence);
 579    if (ret == -1) {
 580        error_setg_errno(errp, errno, "failed to seek file");
 581        if (errno == ESPIPE) {
 582            /* file is non-seekable, stdio shouldn't be buffering anyways */
 583            gfh->state = RW_STATE_NEW;
 584        }
 585    } else {
 586        seek_data = g_new0(GuestFileSeek, 1);
 587        seek_data->position = ftell(fh);
 588        seek_data->eof = feof(fh);
 589        gfh->state = RW_STATE_NEW;
 590    }
 591    clearerr(fh);
 592
 593    return seek_data;
 594}
 595
 596void qmp_guest_file_flush(int64_t handle, Error **errp)
 597{
 598    GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
 599    FILE *fh;
 600    int ret;
 601
 602    if (!gfh) {
 603        return;
 604    }
 605
 606    fh = gfh->fh;
 607    ret = fflush(fh);
 608    if (ret == EOF) {
 609        error_setg_errno(errp, errno, "failed to flush file");
 610    } else {
 611        gfh->state = RW_STATE_NEW;
 612    }
 613}
 614
 615/* linux-specific implementations. avoid this if at all possible. */
 616#if defined(__linux__)
 617
 618#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
 619typedef struct FsMount {
 620    char *dirname;
 621    char *devtype;
 622    unsigned int devmajor, devminor;
 623    QTAILQ_ENTRY(FsMount) next;
 624} FsMount;
 625
 626typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
 627
 628static void free_fs_mount_list(FsMountList *mounts)
 629{
 630     FsMount *mount, *temp;
 631
 632     if (!mounts) {
 633         return;
 634     }
 635
 636     QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
 637         QTAILQ_REMOVE(mounts, mount, next);
 638         g_free(mount->dirname);
 639         g_free(mount->devtype);
 640         g_free(mount);
 641     }
 642}
 643
 644static int dev_major_minor(const char *devpath,
 645                           unsigned int *devmajor, unsigned int *devminor)
 646{
 647    struct stat st;
 648
 649    *devmajor = 0;
 650    *devminor = 0;
 651
 652    if (stat(devpath, &st) < 0) {
 653        slog("failed to stat device file '%s': %s", devpath, strerror(errno));
 654        return -1;
 655    }
 656    if (S_ISDIR(st.st_mode)) {
 657        /* It is bind mount */
 658        return -2;
 659    }
 660    if (S_ISBLK(st.st_mode)) {
 661        *devmajor = major(st.st_rdev);
 662        *devminor = minor(st.st_rdev);
 663        return 0;
 664    }
 665    return -1;
 666}
 667
 668/*
 669 * Walk the mount table and build a list of local file systems
 670 */
 671static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
 672{
 673    struct mntent *ment;
 674    FsMount *mount;
 675    char const *mtab = "/proc/self/mounts";
 676    FILE *fp;
 677    unsigned int devmajor, devminor;
 678
 679    fp = setmntent(mtab, "r");
 680    if (!fp) {
 681        error_setg(errp, "failed to open mtab file: '%s'", mtab);
 682        return;
 683    }
 684
 685    while ((ment = getmntent(fp))) {
 686        /*
 687         * An entry which device name doesn't start with a '/' is
 688         * either a dummy file system or a network file system.
 689         * Add special handling for smbfs and cifs as is done by
 690         * coreutils as well.
 691         */
 692        if ((ment->mnt_fsname[0] != '/') ||
 693            (strcmp(ment->mnt_type, "smbfs") == 0) ||
 694            (strcmp(ment->mnt_type, "cifs") == 0)) {
 695            continue;
 696        }
 697        if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) {
 698            /* Skip bind mounts */
 699            continue;
 700        }
 701
 702        mount = g_new0(FsMount, 1);
 703        mount->dirname = g_strdup(ment->mnt_dir);
 704        mount->devtype = g_strdup(ment->mnt_type);
 705        mount->devmajor = devmajor;
 706        mount->devminor = devminor;
 707
 708        QTAILQ_INSERT_TAIL(mounts, mount, next);
 709    }
 710
 711    endmntent(fp);
 712}
 713
 714static void decode_mntname(char *name, int len)
 715{
 716    int i, j = 0;
 717    for (i = 0; i <= len; i++) {
 718        if (name[i] != '\\') {
 719            name[j++] = name[i];
 720        } else if (name[i + 1] == '\\') {
 721            name[j++] = '\\';
 722            i++;
 723        } else if (name[i + 1] >= '0' && name[i + 1] <= '3' &&
 724                   name[i + 2] >= '0' && name[i + 2] <= '7' &&
 725                   name[i + 3] >= '0' && name[i + 3] <= '7') {
 726            name[j++] = (name[i + 1] - '0') * 64 +
 727                        (name[i + 2] - '0') * 8 +
 728                        (name[i + 3] - '0');
 729            i += 3;
 730        } else {
 731            name[j++] = name[i];
 732        }
 733    }
 734}
 735
 736static void build_fs_mount_list(FsMountList *mounts, Error **errp)
 737{
 738    FsMount *mount;
 739    char const *mountinfo = "/proc/self/mountinfo";
 740    FILE *fp;
 741    char *line = NULL, *dash;
 742    size_t n;
 743    char check;
 744    unsigned int devmajor, devminor;
 745    int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
 746
 747    fp = fopen(mountinfo, "r");
 748    if (!fp) {
 749        build_fs_mount_list_from_mtab(mounts, errp);
 750        return;
 751    }
 752
 753    while (getline(&line, &n, fp) != -1) {
 754        ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c",
 755                     &devmajor, &devminor, &dir_s, &dir_e, &check);
 756        if (ret < 3) {
 757            continue;
 758        }
 759        dash = strstr(line + dir_e, " - ");
 760        if (!dash) {
 761            continue;
 762        }
 763        ret = sscanf(dash, " - %n%*s%n %n%*s%n%c",
 764                     &type_s, &type_e, &dev_s, &dev_e, &check);
 765        if (ret < 1) {
 766            continue;
 767        }
 768        line[dir_e] = 0;
 769        dash[type_e] = 0;
 770        dash[dev_e] = 0;
 771        decode_mntname(line + dir_s, dir_e - dir_s);
 772        decode_mntname(dash + dev_s, dev_e - dev_s);
 773        if (devmajor == 0) {
 774            /* btrfs reports major number = 0 */
 775            if (strcmp("btrfs", dash + type_s) != 0 ||
 776                dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) {
 777                continue;
 778            }
 779        }
 780
 781        mount = g_new0(FsMount, 1);
 782        mount->dirname = g_strdup(line + dir_s);
 783        mount->devtype = g_strdup(dash + type_s);
 784        mount->devmajor = devmajor;
 785        mount->devminor = devminor;
 786
 787        QTAILQ_INSERT_TAIL(mounts, mount, next);
 788    }
 789    free(line);
 790
 791    fclose(fp);
 792}
 793#endif
 794
 795#if defined(CONFIG_FSFREEZE)
 796
 797static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
 798{
 799    char *path;
 800    char *dpath;
 801    char *driver = NULL;
 802    char buf[PATH_MAX];
 803    ssize_t len;
 804
 805    path = g_strndup(syspath, pathlen);
 806    dpath = g_strdup_printf("%s/driver", path);
 807    len = readlink(dpath, buf, sizeof(buf) - 1);
 808    if (len != -1) {
 809        buf[len] = 0;
 810        driver = g_strdup(basename(buf));
 811    }
 812    g_free(dpath);
 813    g_free(path);
 814    return driver;
 815}
 816
 817static int compare_uint(const void *_a, const void *_b)
 818{
 819    unsigned int a = *(unsigned int *)_a;
 820    unsigned int b = *(unsigned int *)_b;
 821
 822    return a < b ? -1 : a > b ? 1 : 0;
 823}
 824
 825/* Walk the specified sysfs and build a sorted list of host or ata numbers */
 826static int build_hosts(char const *syspath, char const *host, bool ata,
 827                       unsigned int *hosts, int hosts_max, Error **errp)
 828{
 829    char *path;
 830    DIR *dir;
 831    struct dirent *entry;
 832    int i = 0;
 833
 834    path = g_strndup(syspath, host - syspath);
 835    dir = opendir(path);
 836    if (!dir) {
 837        error_setg_errno(errp, errno, "opendir(\"%s\")", path);
 838        g_free(path);
 839        return -1;
 840    }
 841
 842    while (i < hosts_max) {
 843        entry = readdir(dir);
 844        if (!entry) {
 845            break;
 846        }
 847        if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
 848            ++i;
 849        } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
 850            ++i;
 851        }
 852    }
 853
 854    qsort(hosts, i, sizeof(hosts[0]), compare_uint);
 855
 856    g_free(path);
 857    closedir(dir);
 858    return i;
 859}
 860
 861/* Store disk device info specified by @sysfs into @fs */
 862static void build_guest_fsinfo_for_real_device(char const *syspath,
 863                                               GuestFilesystemInfo *fs,
 864                                               Error **errp)
 865{
 866    unsigned int pci[4], host, hosts[8], tgt[3];
 867    int i, nhosts = 0, pcilen;
 868    GuestDiskAddress *disk;
 869    GuestPCIAddress *pciaddr;
 870    GuestDiskAddressList *list = NULL;
 871    bool has_ata = false, has_host = false, has_tgt = false;
 872    char *p, *q, *driver = NULL;
 873
 874    p = strstr(syspath, "/devices/pci");
 875    if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
 876                     pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
 877        g_debug("only pci device is supported: sysfs path \"%s\"", syspath);
 878        return;
 879    }
 880
 881    driver = get_pci_driver(syspath, (p + 12 + pcilen) - syspath, errp);
 882    if (!driver) {
 883        goto cleanup;
 884    }
 885
 886    p = strstr(syspath, "/target");
 887    if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
 888                    tgt, tgt + 1, tgt + 2) == 3) {
 889        has_tgt = true;
 890    }
 891
 892    p = strstr(syspath, "/ata");
 893    if (p) {
 894        q = p + 4;
 895        has_ata = true;
 896    } else {
 897        p = strstr(syspath, "/host");
 898        q = p + 5;
 899    }
 900    if (p && sscanf(q, "%u", &host) == 1) {
 901        has_host = true;
 902        nhosts = build_hosts(syspath, p, has_ata, hosts,
 903                             sizeof(hosts) / sizeof(hosts[0]), errp);
 904        if (nhosts < 0) {
 905            goto cleanup;
 906        }
 907    }
 908
 909    pciaddr = g_malloc0(sizeof(*pciaddr));
 910    pciaddr->domain = pci[0];
 911    pciaddr->bus = pci[1];
 912    pciaddr->slot = pci[2];
 913    pciaddr->function = pci[3];
 914
 915    disk = g_malloc0(sizeof(*disk));
 916    disk->pci_controller = pciaddr;
 917
 918    list = g_malloc0(sizeof(*list));
 919    list->value = disk;
 920
 921    if (strcmp(driver, "ata_piix") == 0) {
 922        /* a host per ide bus, target*:0:<unit>:0 */
 923        if (!has_host || !has_tgt) {
 924            g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
 925            goto cleanup;
 926        }
 927        for (i = 0; i < nhosts; i++) {
 928            if (host == hosts[i]) {
 929                disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
 930                disk->bus = i;
 931                disk->unit = tgt[1];
 932                break;
 933            }
 934        }
 935        if (i >= nhosts) {
 936            g_debug("no host for '%s' (driver '%s')", syspath, driver);
 937            goto cleanup;
 938        }
 939    } else if (strcmp(driver, "sym53c8xx") == 0) {
 940        /* scsi(LSI Logic): target*:0:<unit>:0 */
 941        if (!has_tgt) {
 942            g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
 943            goto cleanup;
 944        }
 945        disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
 946        disk->unit = tgt[1];
 947    } else if (strcmp(driver, "virtio-pci") == 0) {
 948        if (has_tgt) {
 949            /* virtio-scsi: target*:0:0:<unit> */
 950            disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
 951            disk->unit = tgt[2];
 952        } else {
 953            /* virtio-blk: 1 disk per 1 device */
 954            disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
 955        }
 956    } else if (strcmp(driver, "ahci") == 0) {
 957        /* ahci: 1 host per 1 unit */
 958        if (!has_host || !has_tgt) {
 959            g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
 960            goto cleanup;
 961        }
 962        for (i = 0; i < nhosts; i++) {
 963            if (host == hosts[i]) {
 964                disk->unit = i;
 965                disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
 966                break;
 967            }
 968        }
 969        if (i >= nhosts) {
 970            g_debug("no host for '%s' (driver '%s')", syspath, driver);
 971            goto cleanup;
 972        }
 973    } else {
 974        g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
 975        goto cleanup;
 976    }
 977
 978    list->next = fs->disk;
 979    fs->disk = list;
 980    g_free(driver);
 981    return;
 982
 983cleanup:
 984    if (list) {
 985        qapi_free_GuestDiskAddressList(list);
 986    }
 987    g_free(driver);
 988}
 989
 990static void build_guest_fsinfo_for_device(char const *devpath,
 991                                          GuestFilesystemInfo *fs,
 992                                          Error **errp);
 993
 994/* Store a list of slave devices of virtual volume specified by @syspath into
 995 * @fs */
 996static void build_guest_fsinfo_for_virtual_device(char const *syspath,
 997                                                  GuestFilesystemInfo *fs,
 998                                                  Error **errp)
 999{
1000    DIR *dir;
1001    char *dirpath;
1002    struct dirent *entry;
1003
1004    dirpath = g_strdup_printf("%s/slaves", syspath);
1005    dir = opendir(dirpath);
1006    if (!dir) {
1007        if (errno != ENOENT) {
1008            error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
1009        }
1010        g_free(dirpath);
1011        return;
1012    }
1013
1014    for (;;) {
1015        errno = 0;
1016        entry = readdir(dir);
1017        if (entry == NULL) {
1018            if (errno) {
1019                error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
1020            }
1021            break;
1022        }
1023
1024        if (entry->d_type == DT_LNK) {
1025            char *path;
1026
1027            g_debug(" slave device '%s'", entry->d_name);
1028            path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
1029            build_guest_fsinfo_for_device(path, fs, errp);
1030            g_free(path);
1031
1032            if (*errp) {
1033                break;
1034            }
1035        }
1036    }
1037
1038    g_free(dirpath);
1039    closedir(dir);
1040}
1041
1042/* Dispatch to functions for virtual/real device */
1043static void build_guest_fsinfo_for_device(char const *devpath,
1044                                          GuestFilesystemInfo *fs,
1045                                          Error **errp)
1046{
1047    char *syspath = realpath(devpath, NULL);
1048
1049    if (!syspath) {
1050        error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
1051        return;
1052    }
1053
1054    if (!fs->name) {
1055        fs->name = g_strdup(basename(syspath));
1056    }
1057
1058    g_debug("  parse sysfs path '%s'", syspath);
1059
1060    if (strstr(syspath, "/devices/virtual/block/")) {
1061        build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
1062    } else {
1063        build_guest_fsinfo_for_real_device(syspath, fs, errp);
1064    }
1065
1066    free(syspath);
1067}
1068
1069/* Return a list of the disk device(s)' info which @mount lies on */
1070static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
1071                                               Error **errp)
1072{
1073    GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
1074    char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
1075                                    mount->devmajor, mount->devminor);
1076
1077    fs->mountpoint = g_strdup(mount->dirname);
1078    fs->type = g_strdup(mount->devtype);
1079    build_guest_fsinfo_for_device(devpath, fs, errp);
1080
1081    g_free(devpath);
1082    return fs;
1083}
1084
1085GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
1086{
1087    FsMountList mounts;
1088    struct FsMount *mount;
1089    GuestFilesystemInfoList *new, *ret = NULL;
1090    Error *local_err = NULL;
1091
1092    QTAILQ_INIT(&mounts);
1093    build_fs_mount_list(&mounts, &local_err);
1094    if (local_err) {
1095        error_propagate(errp, local_err);
1096        return NULL;
1097    }
1098
1099    QTAILQ_FOREACH(mount, &mounts, next) {
1100        g_debug("Building guest fsinfo for '%s'", mount->dirname);
1101
1102        new = g_malloc0(sizeof(*ret));
1103        new->value = build_guest_fsinfo(mount, &local_err);
1104        new->next = ret;
1105        ret = new;
1106        if (local_err) {
1107            error_propagate(errp, local_err);
1108            qapi_free_GuestFilesystemInfoList(ret);
1109            ret = NULL;
1110            break;
1111        }
1112    }
1113
1114    free_fs_mount_list(&mounts);
1115    return ret;
1116}
1117
1118
1119typedef enum {
1120    FSFREEZE_HOOK_THAW = 0,
1121    FSFREEZE_HOOK_FREEZE,
1122} FsfreezeHookArg;
1123
1124static const char *fsfreeze_hook_arg_string[] = {
1125    "thaw",
1126    "freeze",
1127};
1128
1129static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
1130{
1131    int status;
1132    pid_t pid;
1133    const char *hook;
1134    const char *arg_str = fsfreeze_hook_arg_string[arg];
1135    Error *local_err = NULL;
1136
1137    hook = ga_fsfreeze_hook(ga_state);
1138    if (!hook) {
1139        return;
1140    }
1141    if (access(hook, X_OK) != 0) {
1142        error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
1143        return;
1144    }
1145
1146    slog("executing fsfreeze hook with arg '%s'", arg_str);
1147    pid = fork();
1148    if (pid == 0) {
1149        setsid();
1150        reopen_fd_to_null(0);
1151        reopen_fd_to_null(1);
1152        reopen_fd_to_null(2);
1153
1154        execle(hook, hook, arg_str, NULL, environ);
1155        _exit(EXIT_FAILURE);
1156    } else if (pid < 0) {
1157        error_setg_errno(errp, errno, "failed to create child process");
1158        return;
1159    }
1160
1161    ga_wait_child(pid, &status, &local_err);
1162    if (local_err) {
1163        error_propagate(errp, local_err);
1164        return;
1165    }
1166
1167    if (!WIFEXITED(status)) {
1168        error_setg(errp, "fsfreeze hook has terminated abnormally");
1169        return;
1170    }
1171
1172    status = WEXITSTATUS(status);
1173    if (status) {
1174        error_setg(errp, "fsfreeze hook has failed with status %d", status);
1175        return;
1176    }
1177}
1178
1179/*
1180 * Return status of freeze/thaw
1181 */
1182GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
1183{
1184    if (ga_is_frozen(ga_state)) {
1185        return GUEST_FSFREEZE_STATUS_FROZEN;
1186    }
1187
1188    return GUEST_FSFREEZE_STATUS_THAWED;
1189}
1190
1191int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1192{
1193    return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
1194}
1195
1196/*
1197 * Walk list of mounted file systems in the guest, and freeze the ones which
1198 * are real local file systems.
1199 */
1200int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
1201                                       strList *mountpoints,
1202                                       Error **errp)
1203{
1204    int ret = 0, i = 0;
1205    strList *list;
1206    FsMountList mounts;
1207    struct FsMount *mount;
1208    Error *local_err = NULL;
1209    int fd;
1210
1211    slog("guest-fsfreeze called");
1212
1213    execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
1214    if (local_err) {
1215        error_propagate(errp, local_err);
1216        return -1;
1217    }
1218
1219    QTAILQ_INIT(&mounts);
1220    build_fs_mount_list(&mounts, &local_err);
1221    if (local_err) {
1222        error_propagate(errp, local_err);
1223        return -1;
1224    }
1225
1226    /* cannot risk guest agent blocking itself on a write in this state */
1227    ga_set_frozen(ga_state);
1228
1229    QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
1230        /* To issue fsfreeze in the reverse order of mounts, check if the
1231         * mount is listed in the list here */
1232        if (has_mountpoints) {
1233            for (list = mountpoints; list; list = list->next) {
1234                if (strcmp(list->value, mount->dirname) == 0) {
1235                    break;
1236                }
1237            }
1238            if (!list) {
1239                continue;
1240            }
1241        }
1242
1243        fd = qemu_open(mount->dirname, O_RDONLY);
1244        if (fd == -1) {
1245            error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
1246            goto error;
1247        }
1248
1249        /* we try to cull filesystems we know won't work in advance, but other
1250         * filesystems may not implement fsfreeze for less obvious reasons.
1251         * these will report EOPNOTSUPP. we simply ignore these when tallying
1252         * the number of frozen filesystems.
1253         * if a filesystem is mounted more than once (aka bind mount) a
1254         * consecutive attempt to freeze an already frozen filesystem will
1255         * return EBUSY.
1256         *
1257         * any other error means a failure to freeze a filesystem we
1258         * expect to be freezable, so return an error in those cases
1259         * and return system to thawed state.
1260         */
1261        ret = ioctl(fd, FIFREEZE);
1262        if (ret == -1) {
1263            if (errno != EOPNOTSUPP && errno != EBUSY) {
1264                error_setg_errno(errp, errno, "failed to freeze %s",
1265                                 mount->dirname);
1266                close(fd);
1267                goto error;
1268            }
1269        } else {
1270            i++;
1271        }
1272        close(fd);
1273    }
1274
1275    free_fs_mount_list(&mounts);
1276    return i;
1277
1278error:
1279    free_fs_mount_list(&mounts);
1280    qmp_guest_fsfreeze_thaw(NULL);
1281    return 0;
1282}
1283
1284/*
1285 * Walk list of frozen file systems in the guest, and thaw them.
1286 */
1287int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1288{
1289    int ret;
1290    FsMountList mounts;
1291    FsMount *mount;
1292    int fd, i = 0, logged;
1293    Error *local_err = NULL;
1294
1295    QTAILQ_INIT(&mounts);
1296    build_fs_mount_list(&mounts, &local_err);
1297    if (local_err) {
1298        error_propagate(errp, local_err);
1299        return 0;
1300    }
1301
1302    QTAILQ_FOREACH(mount, &mounts, next) {
1303        logged = false;
1304        fd = qemu_open(mount->dirname, O_RDONLY);
1305        if (fd == -1) {
1306            continue;
1307        }
1308        /* we have no way of knowing whether a filesystem was actually unfrozen
1309         * as a result of a successful call to FITHAW, only that if an error
1310         * was returned the filesystem was *not* unfrozen by that particular
1311         * call.
1312         *
1313         * since multiple preceding FIFREEZEs require multiple calls to FITHAW
1314         * to unfreeze, continuing issuing FITHAW until an error is returned,
1315         * in which case either the filesystem is in an unfreezable state, or,
1316         * more likely, it was thawed previously (and remains so afterward).
1317         *
1318         * also, since the most recent successful call is the one that did
1319         * the actual unfreeze, we can use this to provide an accurate count
1320         * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
1321         * may * be useful for determining whether a filesystem was unfrozen
1322         * during the freeze/thaw phase by a process other than qemu-ga.
1323         */
1324        do {
1325            ret = ioctl(fd, FITHAW);
1326            if (ret == 0 && !logged) {
1327                i++;
1328                logged = true;
1329            }
1330        } while (ret == 0);
1331        close(fd);
1332    }
1333
1334    ga_unset_frozen(ga_state);
1335    free_fs_mount_list(&mounts);
1336
1337    execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
1338
1339    return i;
1340}
1341
1342static void guest_fsfreeze_cleanup(void)
1343{
1344    Error *err = NULL;
1345
1346    if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
1347        qmp_guest_fsfreeze_thaw(&err);
1348        if (err) {
1349            slog("failed to clean up frozen filesystems: %s",
1350                 error_get_pretty(err));
1351            error_free(err);
1352        }
1353    }
1354}
1355#endif /* CONFIG_FSFREEZE */
1356
1357#if defined(CONFIG_FSTRIM)
1358/*
1359 * Walk list of mounted file systems in the guest, and trim them.
1360 */
1361GuestFilesystemTrimResponse *
1362qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
1363{
1364    GuestFilesystemTrimResponse *response;
1365    GuestFilesystemTrimResultList *list;
1366    GuestFilesystemTrimResult *result;
1367    int ret = 0;
1368    FsMountList mounts;
1369    struct FsMount *mount;
1370    int fd;
1371    Error *local_err = NULL;
1372    struct fstrim_range r;
1373
1374    slog("guest-fstrim called");
1375
1376    QTAILQ_INIT(&mounts);
1377    build_fs_mount_list(&mounts, &local_err);
1378    if (local_err) {
1379        error_propagate(errp, local_err);
1380        return NULL;
1381    }
1382
1383    response = g_malloc0(sizeof(*response));
1384
1385    QTAILQ_FOREACH(mount, &mounts, next) {
1386        result = g_malloc0(sizeof(*result));
1387        result->path = g_strdup(mount->dirname);
1388
1389        list = g_malloc0(sizeof(*list));
1390        list->value = result;
1391        list->next = response->paths;
1392        response->paths = list;
1393
1394        fd = qemu_open(mount->dirname, O_RDONLY);
1395        if (fd == -1) {
1396            result->error = g_strdup_printf("failed to open: %s",
1397                                            strerror(errno));
1398            result->has_error = true;
1399            continue;
1400        }
1401
1402        /* We try to cull filesystems we know won't work in advance, but other
1403         * filesystems may not implement fstrim for less obvious reasons.
1404         * These will report EOPNOTSUPP; while in some other cases ENOTTY
1405         * will be reported (e.g. CD-ROMs).
1406         * Any other error means an unexpected error.
1407         */
1408        r.start = 0;
1409        r.len = -1;
1410        r.minlen = has_minimum ? minimum : 0;
1411        ret = ioctl(fd, FITRIM, &r);
1412        if (ret == -1) {
1413            result->has_error = true;
1414            if (errno == ENOTTY || errno == EOPNOTSUPP) {
1415                result->error = g_strdup("trim not supported");
1416            } else {
1417                result->error = g_strdup_printf("failed to trim: %s",
1418                                                strerror(errno));
1419            }
1420            close(fd);
1421            continue;
1422        }
1423
1424        result->has_minimum = true;
1425        result->minimum = r.minlen;
1426        result->has_trimmed = true;
1427        result->trimmed = r.len;
1428        close(fd);
1429    }
1430
1431    free_fs_mount_list(&mounts);
1432    return response;
1433}
1434#endif /* CONFIG_FSTRIM */
1435
1436
1437#define LINUX_SYS_STATE_FILE "/sys/power/state"
1438#define SUSPEND_SUPPORTED 0
1439#define SUSPEND_NOT_SUPPORTED 1
1440
1441static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
1442                               const char *sysfile_str, Error **errp)
1443{
1444    Error *local_err = NULL;
1445    char *pmutils_path;
1446    pid_t pid;
1447    int status;
1448
1449    pmutils_path = g_find_program_in_path(pmutils_bin);
1450
1451    pid = fork();
1452    if (!pid) {
1453        char buf[32]; /* hopefully big enough */
1454        ssize_t ret;
1455        int fd;
1456
1457        setsid();
1458        reopen_fd_to_null(0);
1459        reopen_fd_to_null(1);
1460        reopen_fd_to_null(2);
1461
1462        if (pmutils_path) {
1463            execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
1464        }
1465
1466        /*
1467         * If we get here either pm-utils is not installed or execle() has
1468         * failed. Let's try the manual method if the caller wants it.
1469         */
1470
1471        if (!sysfile_str) {
1472            _exit(SUSPEND_NOT_SUPPORTED);
1473        }
1474
1475        fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
1476        if (fd < 0) {
1477            _exit(SUSPEND_NOT_SUPPORTED);
1478        }
1479
1480        ret = read(fd, buf, sizeof(buf)-1);
1481        if (ret <= 0) {
1482            _exit(SUSPEND_NOT_SUPPORTED);
1483        }
1484        buf[ret] = '\0';
1485
1486        if (strstr(buf, sysfile_str)) {
1487            _exit(SUSPEND_SUPPORTED);
1488        }
1489
1490        _exit(SUSPEND_NOT_SUPPORTED);
1491    } else if (pid < 0) {
1492        error_setg_errno(errp, errno, "failed to create child process");
1493        goto out;
1494    }
1495
1496    ga_wait_child(pid, &status, &local_err);
1497    if (local_err) {
1498        error_propagate(errp, local_err);
1499        goto out;
1500    }
1501
1502    if (!WIFEXITED(status)) {
1503        error_setg(errp, "child process has terminated abnormally");
1504        goto out;
1505    }
1506
1507    switch (WEXITSTATUS(status)) {
1508    case SUSPEND_SUPPORTED:
1509        goto out;
1510    case SUSPEND_NOT_SUPPORTED:
1511        error_setg(errp,
1512                   "the requested suspend mode is not supported by the guest");
1513        goto out;
1514    default:
1515        error_setg(errp,
1516                   "the helper program '%s' returned an unexpected exit status"
1517                   " code (%d)", pmutils_path, WEXITSTATUS(status));
1518        goto out;
1519    }
1520
1521out:
1522    g_free(pmutils_path);
1523}
1524
1525static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
1526                          Error **errp)
1527{
1528    Error *local_err = NULL;
1529    char *pmutils_path;
1530    pid_t pid;
1531    int status;
1532
1533    pmutils_path = g_find_program_in_path(pmutils_bin);
1534
1535    pid = fork();
1536    if (pid == 0) {
1537        /* child */
1538        int fd;
1539
1540        setsid();
1541        reopen_fd_to_null(0);
1542        reopen_fd_to_null(1);
1543        reopen_fd_to_null(2);
1544
1545        if (pmutils_path) {
1546            execle(pmutils_path, pmutils_bin, NULL, environ);
1547        }
1548
1549        /*
1550         * If we get here either pm-utils is not installed or execle() has
1551         * failed. Let's try the manual method if the caller wants it.
1552         */
1553
1554        if (!sysfile_str) {
1555            _exit(EXIT_FAILURE);
1556        }
1557
1558        fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
1559        if (fd < 0) {
1560            _exit(EXIT_FAILURE);
1561        }
1562
1563        if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
1564            _exit(EXIT_FAILURE);
1565        }
1566
1567        _exit(EXIT_SUCCESS);
1568    } else if (pid < 0) {
1569        error_setg_errno(errp, errno, "failed to create child process");
1570        goto out;
1571    }
1572
1573    ga_wait_child(pid, &status, &local_err);
1574    if (local_err) {
1575        error_propagate(errp, local_err);
1576        goto out;
1577    }
1578
1579    if (!WIFEXITED(status)) {
1580        error_setg(errp, "child process has terminated abnormally");
1581        goto out;
1582    }
1583
1584    if (WEXITSTATUS(status)) {
1585        error_setg(errp, "child process has failed to suspend");
1586        goto out;
1587    }
1588
1589out:
1590    g_free(pmutils_path);
1591}
1592
1593void qmp_guest_suspend_disk(Error **errp)
1594{
1595    Error *local_err = NULL;
1596
1597    bios_supports_mode("pm-is-supported", "--hibernate", "disk", &local_err);
1598    if (local_err) {
1599        error_propagate(errp, local_err);
1600        return;
1601    }
1602
1603    guest_suspend("pm-hibernate", "disk", errp);
1604}
1605
1606void qmp_guest_suspend_ram(Error **errp)
1607{
1608    Error *local_err = NULL;
1609
1610    bios_supports_mode("pm-is-supported", "--suspend", "mem", &local_err);
1611    if (local_err) {
1612        error_propagate(errp, local_err);
1613        return;
1614    }
1615
1616    guest_suspend("pm-suspend", "mem", errp);
1617}
1618
1619void qmp_guest_suspend_hybrid(Error **errp)
1620{
1621    Error *local_err = NULL;
1622
1623    bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL,
1624                       &local_err);
1625    if (local_err) {
1626        error_propagate(errp, local_err);
1627        return;
1628    }
1629
1630    guest_suspend("pm-suspend-hybrid", NULL, errp);
1631}
1632
1633static GuestNetworkInterfaceList *
1634guest_find_interface(GuestNetworkInterfaceList *head,
1635                     const char *name)
1636{
1637    for (; head; head = head->next) {
1638        if (strcmp(head->value->name, name) == 0) {
1639            break;
1640        }
1641    }
1642
1643    return head;
1644}
1645
1646/*
1647 * Build information about guest interfaces
1648 */
1649GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1650{
1651    GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
1652    struct ifaddrs *ifap, *ifa;
1653
1654    if (getifaddrs(&ifap) < 0) {
1655        error_setg_errno(errp, errno, "getifaddrs failed");
1656        goto error;
1657    }
1658
1659    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1660        GuestNetworkInterfaceList *info;
1661        GuestIpAddressList **address_list = NULL, *address_item = NULL;
1662        char addr4[INET_ADDRSTRLEN];
1663        char addr6[INET6_ADDRSTRLEN];
1664        int sock;
1665        struct ifreq ifr;
1666        unsigned char *mac_addr;
1667        void *p;
1668
1669        g_debug("Processing %s interface", ifa->ifa_name);
1670
1671        info = guest_find_interface(head, ifa->ifa_name);
1672
1673        if (!info) {
1674            info = g_malloc0(sizeof(*info));
1675            info->value = g_malloc0(sizeof(*info->value));
1676            info->value->name = g_strdup(ifa->ifa_name);
1677
1678            if (!cur_item) {
1679                head = cur_item = info;
1680            } else {
1681                cur_item->next = info;
1682                cur_item = info;
1683            }
1684        }
1685
1686        if (!info->value->has_hardware_address &&
1687            ifa->ifa_flags & SIOCGIFHWADDR) {
1688            /* we haven't obtained HW address yet */
1689            sock = socket(PF_INET, SOCK_STREAM, 0);
1690            if (sock == -1) {
1691                error_setg_errno(errp, errno, "failed to create socket");
1692                goto error;
1693            }
1694
1695            memset(&ifr, 0, sizeof(ifr));
1696            pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
1697            if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
1698                error_setg_errno(errp, errno,
1699                                 "failed to get MAC address of %s",
1700                                 ifa->ifa_name);
1701                close(sock);
1702                goto error;
1703            }
1704
1705            close(sock);
1706            mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
1707
1708            info->value->hardware_address =
1709                g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1710                                (int) mac_addr[0], (int) mac_addr[1],
1711                                (int) mac_addr[2], (int) mac_addr[3],
1712                                (int) mac_addr[4], (int) mac_addr[5]);
1713
1714            info->value->has_hardware_address = true;
1715        }
1716
1717        if (ifa->ifa_addr &&
1718            ifa->ifa_addr->sa_family == AF_INET) {
1719            /* interface with IPv4 address */
1720            p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
1721            if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
1722                error_setg_errno(errp, errno, "inet_ntop failed");
1723                goto error;
1724            }
1725
1726            address_item = g_malloc0(sizeof(*address_item));
1727            address_item->value = g_malloc0(sizeof(*address_item->value));
1728            address_item->value->ip_address = g_strdup(addr4);
1729            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
1730
1731            if (ifa->ifa_netmask) {
1732                /* Count the number of set bits in netmask.
1733                 * This is safe as '1' and '0' cannot be shuffled in netmask. */
1734                p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
1735                address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
1736            }
1737        } else if (ifa->ifa_addr &&
1738                   ifa->ifa_addr->sa_family == AF_INET6) {
1739            /* interface with IPv6 address */
1740            p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
1741            if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
1742                error_setg_errno(errp, errno, "inet_ntop failed");
1743                goto error;
1744            }
1745
1746            address_item = g_malloc0(sizeof(*address_item));
1747            address_item->value = g_malloc0(sizeof(*address_item->value));
1748            address_item->value->ip_address = g_strdup(addr6);
1749            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
1750
1751            if (ifa->ifa_netmask) {
1752                /* Count the number of set bits in netmask.
1753                 * This is safe as '1' and '0' cannot be shuffled in netmask. */
1754                p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
1755                address_item->value->prefix =
1756                    ctpop32(((uint32_t *) p)[0]) +
1757                    ctpop32(((uint32_t *) p)[1]) +
1758                    ctpop32(((uint32_t *) p)[2]) +
1759                    ctpop32(((uint32_t *) p)[3]);
1760            }
1761        }
1762
1763        if (!address_item) {
1764            continue;
1765        }
1766
1767        address_list = &info->value->ip_addresses;
1768
1769        while (*address_list && (*address_list)->next) {
1770            address_list = &(*address_list)->next;
1771        }
1772
1773        if (!*address_list) {
1774            *address_list = address_item;
1775        } else {
1776            (*address_list)->next = address_item;
1777        }
1778
1779        info->value->has_ip_addresses = true;
1780
1781
1782    }
1783
1784    freeifaddrs(ifap);
1785    return head;
1786
1787error:
1788    freeifaddrs(ifap);
1789    qapi_free_GuestNetworkInterfaceList(head);
1790    return NULL;
1791}
1792
1793#define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp))
1794
1795static long sysconf_exact(int name, const char *name_str, Error **errp)
1796{
1797    long ret;
1798
1799    errno = 0;
1800    ret = sysconf(name);
1801    if (ret == -1) {
1802        if (errno == 0) {
1803            error_setg(errp, "sysconf(%s): value indefinite", name_str);
1804        } else {
1805            error_setg_errno(errp, errno, "sysconf(%s)", name_str);
1806        }
1807    }
1808    return ret;
1809}
1810
1811/* Transfer online/offline status between @vcpu and the guest system.
1812 *
1813 * On input either @errp or *@errp must be NULL.
1814 *
1815 * In system-to-@vcpu direction, the following @vcpu fields are accessed:
1816 * - R: vcpu->logical_id
1817 * - W: vcpu->online
1818 * - W: vcpu->can_offline
1819 *
1820 * In @vcpu-to-system direction, the following @vcpu fields are accessed:
1821 * - R: vcpu->logical_id
1822 * - R: vcpu->online
1823 *
1824 * Written members remain unmodified on error.
1825 */
1826static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
1827                          Error **errp)
1828{
1829    char *dirpath;
1830    int dirfd;
1831
1832    dirpath = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
1833                              vcpu->logical_id);
1834    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
1835    if (dirfd == -1) {
1836        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
1837    } else {
1838        static const char fn[] = "online";
1839        int fd;
1840        int res;
1841
1842        fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
1843        if (fd == -1) {
1844            if (errno != ENOENT) {
1845                error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
1846            } else if (sys2vcpu) {
1847                vcpu->online = true;
1848                vcpu->can_offline = false;
1849            } else if (!vcpu->online) {
1850                error_setg(errp, "logical processor #%" PRId64 " can't be "
1851                           "offlined", vcpu->logical_id);
1852            } /* otherwise pretend successful re-onlining */
1853        } else {
1854            unsigned char status;
1855
1856            res = pread(fd, &status, 1, 0);
1857            if (res == -1) {
1858                error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
1859            } else if (res == 0) {
1860                error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
1861                           fn);
1862            } else if (sys2vcpu) {
1863                vcpu->online = (status != '0');
1864                vcpu->can_offline = true;
1865            } else if (vcpu->online != (status != '0')) {
1866                status = '0' + vcpu->online;
1867                if (pwrite(fd, &status, 1, 0) == -1) {
1868                    error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
1869                                     fn);
1870                }
1871            } /* otherwise pretend successful re-(on|off)-lining */
1872
1873            res = close(fd);
1874            g_assert(res == 0);
1875        }
1876
1877        res = close(dirfd);
1878        g_assert(res == 0);
1879    }
1880
1881    g_free(dirpath);
1882}
1883
1884GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1885{
1886    int64_t current;
1887    GuestLogicalProcessorList *head, **link;
1888    long sc_max;
1889    Error *local_err = NULL;
1890
1891    current = 0;
1892    head = NULL;
1893    link = &head;
1894    sc_max = SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err);
1895
1896    while (local_err == NULL && current < sc_max) {
1897        GuestLogicalProcessor *vcpu;
1898        GuestLogicalProcessorList *entry;
1899
1900        vcpu = g_malloc0(sizeof *vcpu);
1901        vcpu->logical_id = current++;
1902        vcpu->has_can_offline = true; /* lolspeak ftw */
1903        transfer_vcpu(vcpu, true, &local_err);
1904
1905        entry = g_malloc0(sizeof *entry);
1906        entry->value = vcpu;
1907
1908        *link = entry;
1909        link = &entry->next;
1910    }
1911
1912    if (local_err == NULL) {
1913        /* there's no guest with zero VCPUs */
1914        g_assert(head != NULL);
1915        return head;
1916    }
1917
1918    qapi_free_GuestLogicalProcessorList(head);
1919    error_propagate(errp, local_err);
1920    return NULL;
1921}
1922
1923int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1924{
1925    int64_t processed;
1926    Error *local_err = NULL;
1927
1928    processed = 0;
1929    while (vcpus != NULL) {
1930        transfer_vcpu(vcpus->value, false, &local_err);
1931        if (local_err != NULL) {
1932            break;
1933        }
1934        ++processed;
1935        vcpus = vcpus->next;
1936    }
1937
1938    if (local_err != NULL) {
1939        if (processed == 0) {
1940            error_propagate(errp, local_err);
1941        } else {
1942            error_free(local_err);
1943        }
1944    }
1945
1946    return processed;
1947}
1948
1949void qmp_guest_set_user_password(const char *username,
1950                                 const char *password,
1951                                 bool crypted,
1952                                 Error **errp)
1953{
1954    Error *local_err = NULL;
1955    char *passwd_path = NULL;
1956    pid_t pid;
1957    int status;
1958    int datafd[2] = { -1, -1 };
1959    char *rawpasswddata = NULL;
1960    size_t rawpasswdlen;
1961    char *chpasswddata = NULL;
1962    size_t chpasswdlen;
1963
1964    rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
1965    if (!rawpasswddata) {
1966        return;
1967    }
1968    rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
1969    rawpasswddata[rawpasswdlen] = '\0';
1970
1971    if (strchr(rawpasswddata, '\n')) {
1972        error_setg(errp, "forbidden characters in raw password");
1973        goto out;
1974    }
1975
1976    if (strchr(username, '\n') ||
1977        strchr(username, ':')) {
1978        error_setg(errp, "forbidden characters in username");
1979        goto out;
1980    }
1981
1982    chpasswddata = g_strdup_printf("%s:%s\n", username, rawpasswddata);
1983    chpasswdlen = strlen(chpasswddata);
1984
1985    passwd_path = g_find_program_in_path("chpasswd");
1986
1987    if (!passwd_path) {
1988        error_setg(errp, "cannot find 'passwd' program in PATH");
1989        goto out;
1990    }
1991
1992    if (pipe(datafd) < 0) {
1993        error_setg(errp, "cannot create pipe FDs");
1994        goto out;
1995    }
1996
1997    pid = fork();
1998    if (pid == 0) {
1999        close(datafd[1]);
2000        /* child */
2001        setsid();
2002        dup2(datafd[0], 0);
2003        reopen_fd_to_null(1);
2004        reopen_fd_to_null(2);
2005
2006        if (crypted) {
2007            execle(passwd_path, "chpasswd", "-e", NULL, environ);
2008        } else {
2009            execle(passwd_path, "chpasswd", NULL, environ);
2010        }
2011        _exit(EXIT_FAILURE);
2012    } else if (pid < 0) {
2013        error_setg_errno(errp, errno, "failed to create child process");
2014        goto out;
2015    }
2016    close(datafd[0]);
2017    datafd[0] = -1;
2018
2019    if (qemu_write_full(datafd[1], chpasswddata, chpasswdlen) != chpasswdlen) {
2020        error_setg_errno(errp, errno, "cannot write new account password");
2021        goto out;
2022    }
2023    close(datafd[1]);
2024    datafd[1] = -1;
2025
2026    ga_wait_child(pid, &status, &local_err);
2027    if (local_err) {
2028        error_propagate(errp, local_err);
2029        goto out;
2030    }
2031
2032    if (!WIFEXITED(status)) {
2033        error_setg(errp, "child process has terminated abnormally");
2034        goto out;
2035    }
2036
2037    if (WEXITSTATUS(status)) {
2038        error_setg(errp, "child process has failed to set user password");
2039        goto out;
2040    }
2041
2042out:
2043    g_free(chpasswddata);
2044    g_free(rawpasswddata);
2045    g_free(passwd_path);
2046    if (datafd[0] != -1) {
2047        close(datafd[0]);
2048    }
2049    if (datafd[1] != -1) {
2050        close(datafd[1]);
2051    }
2052}
2053
2054static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
2055                               int size, Error **errp)
2056{
2057    int fd;
2058    int res;
2059
2060    errno = 0;
2061    fd = openat(dirfd, pathname, O_RDONLY);
2062    if (fd == -1) {
2063        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2064        return;
2065    }
2066
2067    res = pread(fd, buf, size, 0);
2068    if (res == -1) {
2069        error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
2070    } else if (res == 0) {
2071        error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
2072    }
2073    close(fd);
2074}
2075
2076static void ga_write_sysfs_file(int dirfd, const char *pathname,
2077                                const char *buf, int size, Error **errp)
2078{
2079    int fd;
2080
2081    errno = 0;
2082    fd = openat(dirfd, pathname, O_WRONLY);
2083    if (fd == -1) {
2084        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2085        return;
2086    }
2087
2088    if (pwrite(fd, buf, size, 0) == -1) {
2089        error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
2090    }
2091
2092    close(fd);
2093}
2094
2095/* Transfer online/offline status between @mem_blk and the guest system.
2096 *
2097 * On input either @errp or *@errp must be NULL.
2098 *
2099 * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
2100 * - R: mem_blk->phys_index
2101 * - W: mem_blk->online
2102 * - W: mem_blk->can_offline
2103 *
2104 * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
2105 * - R: mem_blk->phys_index
2106 * - R: mem_blk->online
2107 *-  R: mem_blk->can_offline
2108 * Written members remain unmodified on error.
2109 */
2110static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
2111                                  GuestMemoryBlockResponse *result,
2112                                  Error **errp)
2113{
2114    char *dirpath;
2115    int dirfd;
2116    char *status;
2117    Error *local_err = NULL;
2118
2119    if (!sys2memblk) {
2120        DIR *dp;
2121
2122        if (!result) {
2123            error_setg(errp, "Internal error, 'result' should not be NULL");
2124            return;
2125        }
2126        errno = 0;
2127        dp = opendir("/sys/devices/system/memory/");
2128         /* if there is no 'memory' directory in sysfs,
2129         * we think this VM does not support online/offline memory block,
2130         * any other solution?
2131         */
2132        if (!dp) {
2133            if (errno == ENOENT) {
2134                result->response =
2135                    GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2136            }
2137            goto out1;
2138        }
2139        closedir(dp);
2140    }
2141
2142    dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
2143                              mem_blk->phys_index);
2144    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2145    if (dirfd == -1) {
2146        if (sys2memblk) {
2147            error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2148        } else {
2149            if (errno == ENOENT) {
2150                result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
2151            } else {
2152                result->response =
2153                    GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2154            }
2155        }
2156        g_free(dirpath);
2157        goto out1;
2158    }
2159    g_free(dirpath);
2160
2161    status = g_malloc0(10);
2162    ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
2163    if (local_err) {
2164        /* treat with sysfs file that not exist in old kernel */
2165        if (errno == ENOENT) {
2166            error_free(local_err);
2167            if (sys2memblk) {
2168                mem_blk->online = true;
2169                mem_blk->can_offline = false;
2170            } else if (!mem_blk->online) {
2171                result->response =
2172                    GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2173            }
2174        } else {
2175            if (sys2memblk) {
2176                error_propagate(errp, local_err);
2177            } else {
2178                result->response =
2179                    GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2180            }
2181        }
2182        goto out2;
2183    }
2184
2185    if (sys2memblk) {
2186        char removable = '0';
2187
2188        mem_blk->online = (strncmp(status, "online", 6) == 0);
2189
2190        ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
2191        if (local_err) {
2192            /* if no 'removable' file, it doesn't support offline mem blk */
2193            if (errno == ENOENT) {
2194                error_free(local_err);
2195                mem_blk->can_offline = false;
2196            } else {
2197                error_propagate(errp, local_err);
2198            }
2199        } else {
2200            mem_blk->can_offline = (removable != '0');
2201        }
2202    } else {
2203        if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
2204            const char *new_state = mem_blk->online ? "online" : "offline";
2205
2206            ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
2207                                &local_err);
2208            if (local_err) {
2209                error_free(local_err);
2210                result->response =
2211                    GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2212                goto out2;
2213            }
2214
2215            result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
2216            result->has_error_code = false;
2217        } /* otherwise pretend successful re-(on|off)-lining */
2218    }
2219    g_free(status);
2220    close(dirfd);
2221    return;
2222
2223out2:
2224    g_free(status);
2225    close(dirfd);
2226out1:
2227    if (!sys2memblk) {
2228        result->has_error_code = true;
2229        result->error_code = errno;
2230    }
2231}
2232
2233GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2234{
2235    GuestMemoryBlockList *head, **link;
2236    Error *local_err = NULL;
2237    struct dirent *de;
2238    DIR *dp;
2239
2240    head = NULL;
2241    link = &head;
2242
2243    dp = opendir("/sys/devices/system/memory/");
2244    if (!dp) {
2245        /* it's ok if this happens to be a system that doesn't expose
2246         * memory blocks via sysfs, but otherwise we should report
2247         * an error
2248         */
2249        if (errno != ENOENT) {
2250            error_setg_errno(errp, errno, "Can't open directory"
2251                             "\"/sys/devices/system/memory/\"");
2252        }
2253        return NULL;
2254    }
2255
2256    /* Note: the phys_index of memory block may be discontinuous,
2257     * this is because a memblk is the unit of the Sparse Memory design, which
2258     * allows discontinuous memory ranges (ex. NUMA), so here we should
2259     * traverse the memory block directory.
2260     */
2261    while ((de = readdir(dp)) != NULL) {
2262        GuestMemoryBlock *mem_blk;
2263        GuestMemoryBlockList *entry;
2264
2265        if ((strncmp(de->d_name, "memory", 6) != 0) ||
2266            !(de->d_type & DT_DIR)) {
2267            continue;
2268        }
2269
2270        mem_blk = g_malloc0(sizeof *mem_blk);
2271        /* The d_name is "memoryXXX",  phys_index is block id, same as XXX */
2272        mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
2273        mem_blk->has_can_offline = true; /* lolspeak ftw */
2274        transfer_memory_block(mem_blk, true, NULL, &local_err);
2275
2276        entry = g_malloc0(sizeof *entry);
2277        entry->value = mem_blk;
2278
2279        *link = entry;
2280        link = &entry->next;
2281    }
2282
2283    closedir(dp);
2284    if (local_err == NULL) {
2285        /* there's no guest with zero memory blocks */
2286        if (head == NULL) {
2287            error_setg(errp, "guest reported zero memory blocks!");
2288        }
2289        return head;
2290    }
2291
2292    qapi_free_GuestMemoryBlockList(head);
2293    error_propagate(errp, local_err);
2294    return NULL;
2295}
2296
2297GuestMemoryBlockResponseList *
2298qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2299{
2300    GuestMemoryBlockResponseList *head, **link;
2301    Error *local_err = NULL;
2302
2303    head = NULL;
2304    link = &head;
2305
2306    while (mem_blks != NULL) {
2307        GuestMemoryBlockResponse *result;
2308        GuestMemoryBlockResponseList *entry;
2309        GuestMemoryBlock *current_mem_blk = mem_blks->value;
2310
2311        result = g_malloc0(sizeof(*result));
2312        result->phys_index = current_mem_blk->phys_index;
2313        transfer_memory_block(current_mem_blk, false, result, &local_err);
2314        if (local_err) { /* should never happen */
2315            goto err;
2316        }
2317        entry = g_malloc0(sizeof *entry);
2318        entry->value = result;
2319
2320        *link = entry;
2321        link = &entry->next;
2322        mem_blks = mem_blks->next;
2323    }
2324
2325    return head;
2326err:
2327    qapi_free_GuestMemoryBlockResponseList(head);
2328    error_propagate(errp, local_err);
2329    return NULL;
2330}
2331
2332GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2333{
2334    Error *local_err = NULL;
2335    char *dirpath;
2336    int dirfd;
2337    char *buf;
2338    GuestMemoryBlockInfo *info;
2339
2340    dirpath = g_strdup_printf("/sys/devices/system/memory/");
2341    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2342    if (dirfd == -1) {
2343        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2344        g_free(dirpath);
2345        return NULL;
2346    }
2347    g_free(dirpath);
2348
2349    buf = g_malloc0(20);
2350    ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
2351    close(dirfd);
2352    if (local_err) {
2353        g_free(buf);
2354        error_propagate(errp, local_err);
2355        return NULL;
2356    }
2357
2358    info = g_new0(GuestMemoryBlockInfo, 1);
2359    info->size = strtol(buf, NULL, 16); /* the unit is bytes */
2360
2361    g_free(buf);
2362
2363    return info;
2364}
2365
2366#else /* defined(__linux__) */
2367
2368void qmp_guest_suspend_disk(Error **errp)
2369{
2370    error_setg(errp, QERR_UNSUPPORTED);
2371}
2372
2373void qmp_guest_suspend_ram(Error **errp)
2374{
2375    error_setg(errp, QERR_UNSUPPORTED);
2376}
2377
2378void qmp_guest_suspend_hybrid(Error **errp)
2379{
2380    error_setg(errp, QERR_UNSUPPORTED);
2381}
2382
2383GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
2384{
2385    error_setg(errp, QERR_UNSUPPORTED);
2386    return NULL;
2387}
2388
2389GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
2390{
2391    error_setg(errp, QERR_UNSUPPORTED);
2392    return NULL;
2393}
2394
2395int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
2396{
2397    error_setg(errp, QERR_UNSUPPORTED);
2398    return -1;
2399}
2400
2401void qmp_guest_set_user_password(const char *username,
2402                                 const char *password,
2403                                 bool crypted,
2404                                 Error **errp)
2405{
2406    error_setg(errp, QERR_UNSUPPORTED);
2407}
2408
2409GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2410{
2411    error_setg(errp, QERR_UNSUPPORTED);
2412    return NULL;
2413}
2414
2415GuestMemoryBlockResponseList *
2416qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2417{
2418    error_setg(errp, QERR_UNSUPPORTED);
2419    return NULL;
2420}
2421
2422GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2423{
2424    error_setg(errp, QERR_UNSUPPORTED);
2425    return NULL;
2426}
2427
2428#endif
2429
2430#if !defined(CONFIG_FSFREEZE)
2431
2432GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
2433{
2434    error_setg(errp, QERR_UNSUPPORTED);
2435    return NULL;
2436}
2437
2438GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
2439{
2440    error_setg(errp, QERR_UNSUPPORTED);
2441
2442    return 0;
2443}
2444
2445int64_t qmp_guest_fsfreeze_freeze(Error **errp)
2446{
2447    error_setg(errp, QERR_UNSUPPORTED);
2448
2449    return 0;
2450}
2451
2452int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
2453                                       strList *mountpoints,
2454                                       Error **errp)
2455{
2456    error_setg(errp, QERR_UNSUPPORTED);
2457
2458    return 0;
2459}
2460
2461int64_t qmp_guest_fsfreeze_thaw(Error **errp)
2462{
2463    error_setg(errp, QERR_UNSUPPORTED);
2464
2465    return 0;
2466}
2467#endif /* CONFIG_FSFREEZE */
2468
2469#if !defined(CONFIG_FSTRIM)
2470GuestFilesystemTrimResponse *
2471qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
2472{
2473    error_setg(errp, QERR_UNSUPPORTED);
2474    return NULL;
2475}
2476#endif
2477
2478/* add unsupported commands to the blacklist */
2479GList *ga_command_blacklist_init(GList *blacklist)
2480{
2481#if !defined(__linux__)
2482    {
2483        const char *list[] = {
2484            "guest-suspend-disk", "guest-suspend-ram",
2485            "guest-suspend-hybrid", "guest-network-get-interfaces",
2486            "guest-get-vcpus", "guest-set-vcpus",
2487            "guest-get-memory-blocks", "guest-set-memory-blocks",
2488            "guest-get-memory-block-size", NULL};
2489        char **p = (char **)list;
2490
2491        while (*p) {
2492            blacklist = g_list_append(blacklist, g_strdup(*p++));
2493        }
2494    }
2495#endif
2496
2497#if !defined(CONFIG_FSFREEZE)
2498    {
2499        const char *list[] = {
2500            "guest-get-fsinfo", "guest-fsfreeze-status",
2501            "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
2502            "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
2503        char **p = (char **)list;
2504
2505        while (*p) {
2506            blacklist = g_list_append(blacklist, g_strdup(*p++));
2507        }
2508    }
2509#endif
2510
2511#if !defined(CONFIG_FSTRIM)
2512    blacklist = g_list_append(blacklist, g_strdup("guest-fstrim"));
2513#endif
2514
2515    return blacklist;
2516}
2517
2518/* register init/cleanup routines for stateful command groups */
2519void ga_command_state_init(GAState *s, GACommandState *cs)
2520{
2521#if defined(CONFIG_FSFREEZE)
2522    ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
2523#endif
2524}
2525
2526#ifdef HAVE_UTMPX
2527
2528#define QGA_MICRO_SECOND_TO_SECOND 1000000
2529
2530static double ga_get_login_time(struct utmpx *user_info)
2531{
2532    double seconds = (double)user_info->ut_tv.tv_sec;
2533    double useconds = (double)user_info->ut_tv.tv_usec;
2534    useconds /= QGA_MICRO_SECOND_TO_SECOND;
2535    return seconds + useconds;
2536}
2537
2538GuestUserList *qmp_guest_get_users(Error **err)
2539{
2540    GHashTable *cache = NULL;
2541    GuestUserList *head = NULL, *cur_item = NULL;
2542    struct utmpx *user_info = NULL;
2543    gpointer value = NULL;
2544    GuestUser *user = NULL;
2545    GuestUserList *item = NULL;
2546    double login_time = 0;
2547
2548    cache = g_hash_table_new(g_str_hash, g_str_equal);
2549    setutxent();
2550
2551    for (;;) {
2552        user_info = getutxent();
2553        if (user_info == NULL) {
2554            break;
2555        } else if (user_info->ut_type != USER_PROCESS) {
2556            continue;
2557        } else if (g_hash_table_contains(cache, user_info->ut_user)) {
2558            value = g_hash_table_lookup(cache, user_info->ut_user);
2559            user = (GuestUser *)value;
2560            login_time = ga_get_login_time(user_info);
2561            /* We're ensuring the earliest login time to be sent */
2562            if (login_time < user->login_time) {
2563                user->login_time = login_time;
2564            }
2565            continue;
2566        }
2567
2568        item = g_new0(GuestUserList, 1);
2569        item->value = g_new0(GuestUser, 1);
2570        item->value->user = g_strdup(user_info->ut_user);
2571        item->value->login_time = ga_get_login_time(user_info);
2572
2573        g_hash_table_insert(cache, item->value->user, item->value);
2574
2575        if (!cur_item) {
2576            head = cur_item = item;
2577        } else {
2578            cur_item->next = item;
2579            cur_item = item;
2580        }
2581    }
2582    endutxent();
2583    g_hash_table_destroy(cache);
2584    return head;
2585}
2586
2587#else
2588
2589GuestUserList *qmp_guest_get_users(Error **errp)
2590{
2591    error_setg(errp, QERR_UNSUPPORTED);
2592    return NULL;
2593}
2594
2595#endif
2596
2597/* Replace escaped special characters with theire real values. The replacement
2598 * is done in place -- returned value is in the original string.
2599 */
2600static void ga_osrelease_replace_special(gchar *value)
2601{
2602    gchar *p, *p2, quote;
2603
2604    /* Trim the string at first space or semicolon if it is not enclosed in
2605     * single or double quotes. */
2606    if ((value[0] != '"') || (value[0] == '\'')) {
2607        p = strchr(value, ' ');
2608        if (p != NULL) {
2609            *p = 0;
2610        }
2611        p = strchr(value, ';');
2612        if (p != NULL) {
2613            *p = 0;
2614        }
2615        return;
2616    }
2617
2618    quote = value[0];
2619    p2 = value;
2620    p = value + 1;
2621    while (*p != 0) {
2622        if (*p == '\\') {
2623            p++;
2624            switch (*p) {
2625            case '$':
2626            case '\'':
2627            case '"':
2628            case '\\':
2629            case '`':
2630                break;
2631            default:
2632                /* Keep literal backslash followed by whatever is there */
2633                p--;
2634                break;
2635            }
2636        } else if (*p == quote) {
2637            *p2 = 0;
2638            break;
2639        }
2640        *(p2++) = *(p++);
2641    }
2642}
2643
2644static GKeyFile *ga_parse_osrelease(const char *fname)
2645{
2646    gchar *content = NULL;
2647    gchar *content2 = NULL;
2648    GError *err = NULL;
2649    GKeyFile *keys = g_key_file_new();
2650    const char *group = "[os-release]\n";
2651
2652    if (!g_file_get_contents(fname, &content, NULL, &err)) {
2653        slog("failed to read '%s', error: %s", fname, err->message);
2654        goto fail;
2655    }
2656
2657    if (!g_utf8_validate(content, -1, NULL)) {
2658        slog("file is not utf-8 encoded: %s", fname);
2659        goto fail;
2660    }
2661    content2 = g_strdup_printf("%s%s", group, content);
2662
2663    if (!g_key_file_load_from_data(keys, content2, -1, G_KEY_FILE_NONE,
2664                                   &err)) {
2665        slog("failed to parse file '%s', error: %s", fname, err->message);
2666        goto fail;
2667    }
2668
2669    g_free(content);
2670    g_free(content2);
2671    return keys;
2672
2673fail:
2674    g_error_free(err);
2675    g_free(content);
2676    g_free(content2);
2677    g_key_file_free(keys);
2678    return NULL;
2679}
2680
2681GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
2682{
2683    GuestOSInfo *info = NULL;
2684    struct utsname kinfo;
2685    GKeyFile *osrelease = NULL;
2686    const char *qga_os_release = g_getenv("QGA_OS_RELEASE");
2687
2688    info = g_new0(GuestOSInfo, 1);
2689
2690    if (uname(&kinfo) != 0) {
2691        error_setg_errno(errp, errno, "uname failed");
2692    } else {
2693        info->has_kernel_version = true;
2694        info->kernel_version = g_strdup(kinfo.version);
2695        info->has_kernel_release = true;
2696        info->kernel_release = g_strdup(kinfo.release);
2697        info->has_machine = true;
2698        info->machine = g_strdup(kinfo.machine);
2699    }
2700
2701    if (qga_os_release != NULL) {
2702        osrelease = ga_parse_osrelease(qga_os_release);
2703    } else {
2704        osrelease = ga_parse_osrelease("/etc/os-release");
2705        if (osrelease == NULL) {
2706            osrelease = ga_parse_osrelease("/usr/lib/os-release");
2707        }
2708    }
2709
2710    if (osrelease != NULL) {
2711        char *value;
2712
2713#define GET_FIELD(field, osfield) do { \
2714    value = g_key_file_get_value(osrelease, "os-release", osfield, NULL); \
2715    if (value != NULL) { \
2716        ga_osrelease_replace_special(value); \
2717        info->has_ ## field = true; \
2718        info->field = value; \
2719    } \
2720} while (0)
2721        GET_FIELD(id, "ID");
2722        GET_FIELD(name, "NAME");
2723        GET_FIELD(pretty_name, "PRETTY_NAME");
2724        GET_FIELD(version, "VERSION");
2725        GET_FIELD(version_id, "VERSION_ID");
2726        GET_FIELD(variant, "VARIANT");
2727        GET_FIELD(variant_id, "VARIANT_ID");
2728#undef GET_FIELD
2729
2730        g_key_file_free(osrelease);
2731    }
2732
2733    return info;
2734}
2735