Statistics
| Branch: | Revision:

root / qga / commands-posix.c @ 878a0ae0

History | View | Annotate | Download (25.9 kB)

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 <glib.h>
15
#include <sys/types.h>
16
#include <sys/ioctl.h>
17
#include <sys/wait.h>
18
#include "qga/guest-agent-core.h"
19
#include "qga-qmp-commands.h"
20
#include "qapi/qmp/qerror.h"
21
#include "qemu/queue.h"
22
#include "qemu/host-utils.h"
23

    
24
#ifndef CONFIG_HAS_ENVIRON
25
#ifdef __APPLE__
26
#include <crt_externs.h>
27
#define environ (*_NSGetEnviron())
28
#else
29
extern char **environ;
30
#endif
31
#endif
32

    
33
#if defined(__linux__)
34
#include <mntent.h>
35
#include <linux/fs.h>
36
#include <ifaddrs.h>
37
#include <arpa/inet.h>
38
#include <sys/socket.h>
39
#include <net/if.h>
40

    
41
#ifdef FIFREEZE
42
#define CONFIG_FSFREEZE
43
#endif
44
#ifdef FITRIM
45
#define CONFIG_FSTRIM
46
#endif
47
#endif
48

    
49
static void ga_wait_child(pid_t pid, int *status, Error **err)
50
{
51
    pid_t rpid;
52

    
53
    *status = 0;
54

    
55
    do {
56
        rpid = waitpid(pid, status, 0);
57
    } while (rpid == -1 && errno == EINTR);
58

    
59
    if (rpid == -1) {
60
        error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid);
61
        return;
62
    }
63

    
64
    g_assert(rpid == pid);
65
}
66

    
67
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
68
{
69
    const char *shutdown_flag;
70
    Error *local_err = NULL;
71
    pid_t pid;
72
    int status;
73

    
74
    slog("guest-shutdown called, mode: %s", mode);
75
    if (!has_mode || strcmp(mode, "powerdown") == 0) {
76
        shutdown_flag = "-P";
77
    } else if (strcmp(mode, "halt") == 0) {
78
        shutdown_flag = "-H";
79
    } else if (strcmp(mode, "reboot") == 0) {
80
        shutdown_flag = "-r";
81
    } else {
82
        error_setg(err,
83
                   "mode is invalid (valid values are: halt|powerdown|reboot");
84
        return;
85
    }
86

    
87
    pid = fork();
88
    if (pid == 0) {
89
        /* child, start the shutdown */
90
        setsid();
91
        reopen_fd_to_null(0);
92
        reopen_fd_to_null(1);
93
        reopen_fd_to_null(2);
94

    
95
        execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
96
               "hypervisor initiated shutdown", (char*)NULL, environ);
97
        _exit(EXIT_FAILURE);
98
    } else if (pid < 0) {
99
        error_setg_errno(err, errno, "failed to create child process");
100
        return;
101
    }
102

    
103
    ga_wait_child(pid, &status, &local_err);
104
    if (error_is_set(&local_err)) {
105
        error_propagate(err, local_err);
106
        return;
107
    }
108

    
109
    if (!WIFEXITED(status)) {
110
        error_setg(err, "child process has terminated abnormally");
111
        return;
112
    }
113

    
114
    if (WEXITSTATUS(status)) {
115
        error_setg(err, "child process has failed to shutdown");
116
        return;
117
    }
118

    
119
    /* succeded */
120
}
121

    
122
typedef struct GuestFileHandle {
123
    uint64_t id;
124
    FILE *fh;
125
    QTAILQ_ENTRY(GuestFileHandle) next;
126
} GuestFileHandle;
127

    
128
static struct {
129
    QTAILQ_HEAD(, GuestFileHandle) filehandles;
130
} guest_file_state;
131

    
132
static void guest_file_handle_add(FILE *fh)
133
{
134
    GuestFileHandle *gfh;
135

    
136
    gfh = g_malloc0(sizeof(GuestFileHandle));
137
    gfh->id = fileno(fh);
138
    gfh->fh = fh;
139
    QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
140
}
141

    
142
static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
143
{
144
    GuestFileHandle *gfh;
145

    
146
    QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
147
    {
148
        if (gfh->id == id) {
149
            return gfh;
150
        }
151
    }
152

    
153
    error_setg(err, "handle '%" PRId64 "' has not been found", id);
154
    return NULL;
155
}
156

    
157
int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
158
{
159
    FILE *fh;
160
    int fd;
161
    int64_t ret = -1;
162

    
163
    if (!has_mode) {
164
        mode = "r";
165
    }
166
    slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
167
    fh = fopen(path, mode);
168
    if (!fh) {
169
        error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
170
                         path, mode);
171
        return -1;
172
    }
173

    
174
    /* set fd non-blocking to avoid common use cases (like reading from a
175
     * named pipe) from hanging the agent
176
     */
177
    fd = fileno(fh);
178
    ret = fcntl(fd, F_GETFL);
179
    ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
180
    if (ret == -1) {
181
        error_setg_errno(err, errno, "failed to make file '%s' non-blocking",
182
                         path);
183
        fclose(fh);
184
        return -1;
185
    }
186

    
187
    guest_file_handle_add(fh);
188
    slog("guest-file-open, handle: %d", fd);
189
    return fd;
190
}
191

    
192
void qmp_guest_file_close(int64_t handle, Error **err)
193
{
194
    GuestFileHandle *gfh = guest_file_handle_find(handle, err);
195
    int ret;
196

    
197
    slog("guest-file-close called, handle: %ld", handle);
198
    if (!gfh) {
199
        return;
200
    }
201

    
202
    ret = fclose(gfh->fh);
203
    if (ret == EOF) {
204
        error_setg_errno(err, errno, "failed to close handle");
205
        return;
206
    }
207

    
208
    QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
209
    g_free(gfh);
210
}
211

    
212
struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
213
                                          int64_t count, Error **err)
214
{
215
    GuestFileHandle *gfh = guest_file_handle_find(handle, err);
216
    GuestFileRead *read_data = NULL;
217
    guchar *buf;
218
    FILE *fh;
219
    size_t read_count;
220

    
221
    if (!gfh) {
222
        return NULL;
223
    }
224

    
225
    if (!has_count) {
226
        count = QGA_READ_COUNT_DEFAULT;
227
    } else if (count < 0) {
228
        error_setg(err, "value '%" PRId64 "' is invalid for argument count",
229
                   count);
230
        return NULL;
231
    }
232

    
233
    fh = gfh->fh;
234
    buf = g_malloc0(count+1);
235
    read_count = fread(buf, 1, count, fh);
236
    if (ferror(fh)) {
237
        error_setg_errno(err, errno, "failed to read file");
238
        slog("guest-file-read failed, handle: %ld", handle);
239
    } else {
240
        buf[read_count] = 0;
241
        read_data = g_malloc0(sizeof(GuestFileRead));
242
        read_data->count = read_count;
243
        read_data->eof = feof(fh);
244
        if (read_count) {
245
            read_data->buf_b64 = g_base64_encode(buf, read_count);
246
        }
247
    }
248
    g_free(buf);
249
    clearerr(fh);
250

    
251
    return read_data;
252
}
253

    
254
GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
255
                                     bool has_count, int64_t count, Error **err)
256
{
257
    GuestFileWrite *write_data = NULL;
258
    guchar *buf;
259
    gsize buf_len;
260
    int write_count;
261
    GuestFileHandle *gfh = guest_file_handle_find(handle, err);
262
    FILE *fh;
263

    
264
    if (!gfh) {
265
        return NULL;
266
    }
267

    
268
    fh = gfh->fh;
269
    buf = g_base64_decode(buf_b64, &buf_len);
270

    
271
    if (!has_count) {
272
        count = buf_len;
273
    } else if (count < 0 || count > buf_len) {
274
        error_setg(err, "value '%" PRId64 "' is invalid for argument count",
275
                   count);
276
        g_free(buf);
277
        return NULL;
278
    }
279

    
280
    write_count = fwrite(buf, 1, count, fh);
281
    if (ferror(fh)) {
282
        error_setg_errno(err, errno, "failed to write to file");
283
        slog("guest-file-write failed, handle: %ld", handle);
284
    } else {
285
        write_data = g_malloc0(sizeof(GuestFileWrite));
286
        write_data->count = write_count;
287
        write_data->eof = feof(fh);
288
    }
289
    g_free(buf);
290
    clearerr(fh);
291

    
292
    return write_data;
293
}
294

    
295
struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
296
                                          int64_t whence, Error **err)
297
{
298
    GuestFileHandle *gfh = guest_file_handle_find(handle, err);
299
    GuestFileSeek *seek_data = NULL;
300
    FILE *fh;
301
    int ret;
302

    
303
    if (!gfh) {
304
        return NULL;
305
    }
306

    
307
    fh = gfh->fh;
308
    ret = fseek(fh, offset, whence);
309
    if (ret == -1) {
310
        error_setg_errno(err, errno, "failed to seek file");
311
    } else {
312
        seek_data = g_malloc0(sizeof(GuestFileRead));
313
        seek_data->position = ftell(fh);
314
        seek_data->eof = feof(fh);
315
    }
316
    clearerr(fh);
317

    
318
    return seek_data;
319
}
320

    
321
void qmp_guest_file_flush(int64_t handle, Error **err)
322
{
323
    GuestFileHandle *gfh = guest_file_handle_find(handle, err);
324
    FILE *fh;
325
    int ret;
326

    
327
    if (!gfh) {
328
        return;
329
    }
330

    
331
    fh = gfh->fh;
332
    ret = fflush(fh);
333
    if (ret == EOF) {
334
        error_setg_errno(err, errno, "failed to flush file");
335
    }
336
}
337

    
338
static void guest_file_init(void)
339
{
340
    QTAILQ_INIT(&guest_file_state.filehandles);
341
}
342

    
343
/* linux-specific implementations. avoid this if at all possible. */
344
#if defined(__linux__)
345

    
346
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
347
typedef struct FsMount {
348
    char *dirname;
349
    char *devtype;
350
    QTAILQ_ENTRY(FsMount) next;
351
} FsMount;
352

    
353
typedef QTAILQ_HEAD(, FsMount) FsMountList;
354

    
355
static void free_fs_mount_list(FsMountList *mounts)
356
{
357
     FsMount *mount, *temp;
358

    
359
     if (!mounts) {
360
         return;
361
     }
362

    
363
     QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
364
         QTAILQ_REMOVE(mounts, mount, next);
365
         g_free(mount->dirname);
366
         g_free(mount->devtype);
367
         g_free(mount);
368
     }
369
}
370

    
371
/*
372
 * Walk the mount table and build a list of local file systems
373
 */
374
static void build_fs_mount_list(FsMountList *mounts, Error **err)
375
{
376
    struct mntent *ment;
377
    FsMount *mount;
378
    char const *mtab = "/proc/self/mounts";
379
    FILE *fp;
380

    
381
    fp = setmntent(mtab, "r");
382
    if (!fp) {
383
        error_setg(err, "failed to open mtab file: '%s'", mtab);
384
        return;
385
    }
386

    
387
    while ((ment = getmntent(fp))) {
388
        /*
389
         * An entry which device name doesn't start with a '/' is
390
         * either a dummy file system or a network file system.
391
         * Add special handling for smbfs and cifs as is done by
392
         * coreutils as well.
393
         */
394
        if ((ment->mnt_fsname[0] != '/') ||
395
            (strcmp(ment->mnt_type, "smbfs") == 0) ||
396
            (strcmp(ment->mnt_type, "cifs") == 0)) {
397
            continue;
398
        }
399

    
400
        mount = g_malloc0(sizeof(FsMount));
401
        mount->dirname = g_strdup(ment->mnt_dir);
402
        mount->devtype = g_strdup(ment->mnt_type);
403

    
404
        QTAILQ_INSERT_TAIL(mounts, mount, next);
405
    }
406

    
407
    endmntent(fp);
408
}
409
#endif
410

    
411
#if defined(CONFIG_FSFREEZE)
412

    
413
/*
414
 * Return status of freeze/thaw
415
 */
416
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
417
{
418
    if (ga_is_frozen(ga_state)) {
419
        return GUEST_FSFREEZE_STATUS_FROZEN;
420
    }
421

    
422
    return GUEST_FSFREEZE_STATUS_THAWED;
423
}
424

    
425
/*
426
 * Walk list of mounted file systems in the guest, and freeze the ones which
427
 * are real local file systems.
428
 */
429
int64_t qmp_guest_fsfreeze_freeze(Error **err)
430
{
431
    int ret = 0, i = 0;
432
    FsMountList mounts;
433
    struct FsMount *mount;
434
    Error *local_err = NULL;
435
    int fd;
436

    
437
    slog("guest-fsfreeze called");
438

    
439
    QTAILQ_INIT(&mounts);
440
    build_fs_mount_list(&mounts, &local_err);
441
    if (error_is_set(&local_err)) {
442
        error_propagate(err, local_err);
443
        return -1;
444
    }
445

    
446
    /* cannot risk guest agent blocking itself on a write in this state */
447
    ga_set_frozen(ga_state);
448

    
449
    QTAILQ_FOREACH(mount, &mounts, next) {
450
        fd = qemu_open(mount->dirname, O_RDONLY);
451
        if (fd == -1) {
452
            error_setg_errno(err, errno, "failed to open %s", mount->dirname);
453
            goto error;
454
        }
455

    
456
        /* we try to cull filesytems we know won't work in advance, but other
457
         * filesytems may not implement fsfreeze for less obvious reasons.
458
         * these will report EOPNOTSUPP. we simply ignore these when tallying
459
         * the number of frozen filesystems.
460
         *
461
         * any other error means a failure to freeze a filesystem we
462
         * expect to be freezable, so return an error in those cases
463
         * and return system to thawed state.
464
         */
465
        ret = ioctl(fd, FIFREEZE);
466
        if (ret == -1) {
467
            if (errno != EOPNOTSUPP) {
468
                error_setg_errno(err, errno, "failed to freeze %s",
469
                                 mount->dirname);
470
                close(fd);
471
                goto error;
472
            }
473
        } else {
474
            i++;
475
        }
476
        close(fd);
477
    }
478

    
479
    free_fs_mount_list(&mounts);
480
    return i;
481

    
482
error:
483
    free_fs_mount_list(&mounts);
484
    qmp_guest_fsfreeze_thaw(NULL);
485
    return 0;
486
}
487

    
488
/*
489
 * Walk list of frozen file systems in the guest, and thaw them.
490
 */
491
int64_t qmp_guest_fsfreeze_thaw(Error **err)
492
{
493
    int ret;
494
    FsMountList mounts;
495
    FsMount *mount;
496
    int fd, i = 0, logged;
497
    Error *local_err = NULL;
498

    
499
    QTAILQ_INIT(&mounts);
500
    build_fs_mount_list(&mounts, &local_err);
501
    if (error_is_set(&local_err)) {
502
        error_propagate(err, local_err);
503
        return 0;
504
    }
505

    
506
    QTAILQ_FOREACH(mount, &mounts, next) {
507
        logged = false;
508
        fd = qemu_open(mount->dirname, O_RDONLY);
509
        if (fd == -1) {
510
            continue;
511
        }
512
        /* we have no way of knowing whether a filesystem was actually unfrozen
513
         * as a result of a successful call to FITHAW, only that if an error
514
         * was returned the filesystem was *not* unfrozen by that particular
515
         * call.
516
         *
517
         * since multiple preceding FIFREEZEs require multiple calls to FITHAW
518
         * to unfreeze, continuing issuing FITHAW until an error is returned,
519
         * in which case either the filesystem is in an unfreezable state, or,
520
         * more likely, it was thawed previously (and remains so afterward).
521
         *
522
         * also, since the most recent successful call is the one that did
523
         * the actual unfreeze, we can use this to provide an accurate count
524
         * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
525
         * may * be useful for determining whether a filesystem was unfrozen
526
         * during the freeze/thaw phase by a process other than qemu-ga.
527
         */
528
        do {
529
            ret = ioctl(fd, FITHAW);
530
            if (ret == 0 && !logged) {
531
                i++;
532
                logged = true;
533
            }
534
        } while (ret == 0);
535
        close(fd);
536
    }
537

    
538
    ga_unset_frozen(ga_state);
539
    free_fs_mount_list(&mounts);
540
    return i;
541
}
542

    
543
static void guest_fsfreeze_cleanup(void)
544
{
545
    int64_t ret;
546
    Error *err = NULL;
547

    
548
    if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
549
        ret = qmp_guest_fsfreeze_thaw(&err);
550
        if (ret < 0 || err) {
551
            slog("failed to clean up frozen filesystems");
552
        }
553
    }
554
}
555
#endif /* CONFIG_FSFREEZE */
556

    
557
#if defined(CONFIG_FSTRIM)
558
/*
559
 * Walk list of mounted file systems in the guest, and trim them.
560
 */
561
void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
562
{
563
    int ret = 0;
564
    FsMountList mounts;
565
    struct FsMount *mount;
566
    int fd;
567
    Error *local_err = NULL;
568
    struct fstrim_range r = {
569
        .start = 0,
570
        .len = -1,
571
        .minlen = has_minimum ? minimum : 0,
572
    };
573

    
574
    slog("guest-fstrim called");
575

    
576
    QTAILQ_INIT(&mounts);
577
    build_fs_mount_list(&mounts, &local_err);
578
    if (error_is_set(&local_err)) {
579
        error_propagate(err, local_err);
580
        return;
581
    }
582

    
583
    QTAILQ_FOREACH(mount, &mounts, next) {
584
        fd = qemu_open(mount->dirname, O_RDONLY);
585
        if (fd == -1) {
586
            error_setg_errno(err, errno, "failed to open %s", mount->dirname);
587
            goto error;
588
        }
589

    
590
        /* We try to cull filesytems we know won't work in advance, but other
591
         * filesytems may not implement fstrim for less obvious reasons.  These
592
         * will report EOPNOTSUPP; we simply ignore these errors.  Any other
593
         * error means an unexpected error, so return it in those cases.  In
594
         * some other cases ENOTTY will be reported (e.g. CD-ROMs).
595
         */
596
        ret = ioctl(fd, FITRIM, &r);
597
        if (ret == -1) {
598
            if (errno != ENOTTY && errno != EOPNOTSUPP) {
599
                error_setg_errno(err, errno, "failed to trim %s",
600
                                 mount->dirname);
601
                close(fd);
602
                goto error;
603
            }
604
        }
605
        close(fd);
606
    }
607

    
608
error:
609
    free_fs_mount_list(&mounts);
610
}
611
#endif /* CONFIG_FSTRIM */
612

    
613

    
614
#define LINUX_SYS_STATE_FILE "/sys/power/state"
615
#define SUSPEND_SUPPORTED 0
616
#define SUSPEND_NOT_SUPPORTED 1
617

    
618
static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
619
                               const char *sysfile_str, Error **err)
620
{
621
    char *pmutils_path;
622
    pid_t pid, rpid;
623
    int status;
624

    
625
    pmutils_path = g_find_program_in_path(pmutils_bin);
626

    
627
    pid = fork();
628
    if (!pid) {
629
        char buf[32]; /* hopefully big enough */
630
        ssize_t ret;
631
        int fd;
632

    
633
        setsid();
634
        reopen_fd_to_null(0);
635
        reopen_fd_to_null(1);
636
        reopen_fd_to_null(2);
637

    
638
        if (pmutils_path) {
639
            execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
640
        }
641

    
642
        /*
643
         * If we get here either pm-utils is not installed or execle() has
644
         * failed. Let's try the manual method if the caller wants it.
645
         */
646

    
647
        if (!sysfile_str) {
648
            _exit(SUSPEND_NOT_SUPPORTED);
649
        }
650

    
651
        fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
652
        if (fd < 0) {
653
            _exit(SUSPEND_NOT_SUPPORTED);
654
        }
655

    
656
        ret = read(fd, buf, sizeof(buf)-1);
657
        if (ret <= 0) {
658
            _exit(SUSPEND_NOT_SUPPORTED);
659
        }
660
        buf[ret] = '\0';
661

    
662
        if (strstr(buf, sysfile_str)) {
663
            _exit(SUSPEND_SUPPORTED);
664
        }
665

    
666
        _exit(SUSPEND_NOT_SUPPORTED);
667
    }
668

    
669
    g_free(pmutils_path);
670

    
671
    if (pid < 0) {
672
        goto undef_err;
673
    }
674

    
675
    do {
676
        rpid = waitpid(pid, &status, 0);
677
    } while (rpid == -1 && errno == EINTR);
678
    if (rpid == pid && WIFEXITED(status)) {
679
        switch (WEXITSTATUS(status)) {
680
        case SUSPEND_SUPPORTED:
681
            return;
682
        case SUSPEND_NOT_SUPPORTED:
683
            error_set(err, QERR_UNSUPPORTED);
684
            return;
685
        default:
686
            goto undef_err;
687
        }
688
    }
689

    
690
undef_err:
691
    error_set(err, QERR_UNDEFINED_ERROR);
692
}
693

    
694
static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
695
                          Error **err)
696
{
697
    char *pmutils_path;
698
    pid_t rpid, pid;
699
    int status;
700

    
701
    pmutils_path = g_find_program_in_path(pmutils_bin);
702

    
703
    pid = fork();
704
    if (pid == 0) {
705
        /* child */
706
        int fd;
707

    
708
        setsid();
709
        reopen_fd_to_null(0);
710
        reopen_fd_to_null(1);
711
        reopen_fd_to_null(2);
712

    
713
        if (pmutils_path) {
714
            execle(pmutils_path, pmutils_bin, NULL, environ);
715
        }
716

    
717
        /*
718
         * If we get here either pm-utils is not installed or execle() has
719
         * failed. Let's try the manual method if the caller wants it.
720
         */
721

    
722
        if (!sysfile_str) {
723
            _exit(EXIT_FAILURE);
724
        }
725

    
726
        fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
727
        if (fd < 0) {
728
            _exit(EXIT_FAILURE);
729
        }
730

    
731
        if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
732
            _exit(EXIT_FAILURE);
733
        }
734

    
735
        _exit(EXIT_SUCCESS);
736
    }
737

    
738
    g_free(pmutils_path);
739

    
740
    if (pid < 0) {
741
        goto exit_err;
742
    }
743

    
744
    do {
745
        rpid = waitpid(pid, &status, 0);
746
    } while (rpid == -1 && errno == EINTR);
747
    if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
748
        return;
749
    }
750

    
751
exit_err:
752
    error_set(err, QERR_UNDEFINED_ERROR);
753
}
754

    
755
void qmp_guest_suspend_disk(Error **err)
756
{
757
    bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
758
    if (error_is_set(err)) {
759
        return;
760
    }
761

    
762
    guest_suspend("pm-hibernate", "disk", err);
763
}
764

    
765
void qmp_guest_suspend_ram(Error **err)
766
{
767
    bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
768
    if (error_is_set(err)) {
769
        return;
770
    }
771

    
772
    guest_suspend("pm-suspend", "mem", err);
773
}
774

    
775
void qmp_guest_suspend_hybrid(Error **err)
776
{
777
    bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
778
    if (error_is_set(err)) {
779
        return;
780
    }
781

    
782
    guest_suspend("pm-suspend-hybrid", NULL, err);
783
}
784

    
785
static GuestNetworkInterfaceList *
786
guest_find_interface(GuestNetworkInterfaceList *head,
787
                     const char *name)
788
{
789
    for (; head; head = head->next) {
790
        if (strcmp(head->value->name, name) == 0) {
791
            break;
792
        }
793
    }
794

    
795
    return head;
796
}
797

    
798
/*
799
 * Build information about guest interfaces
800
 */
801
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
802
{
803
    GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
804
    struct ifaddrs *ifap, *ifa;
805

    
806
    if (getifaddrs(&ifap) < 0) {
807
        error_setg_errno(errp, errno, "getifaddrs failed");
808
        goto error;
809
    }
810

    
811
    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
812
        GuestNetworkInterfaceList *info;
813
        GuestIpAddressList **address_list = NULL, *address_item = NULL;
814
        char addr4[INET_ADDRSTRLEN];
815
        char addr6[INET6_ADDRSTRLEN];
816
        int sock;
817
        struct ifreq ifr;
818
        unsigned char *mac_addr;
819
        void *p;
820

    
821
        g_debug("Processing %s interface", ifa->ifa_name);
822

    
823
        info = guest_find_interface(head, ifa->ifa_name);
824

    
825
        if (!info) {
826
            info = g_malloc0(sizeof(*info));
827
            info->value = g_malloc0(sizeof(*info->value));
828
            info->value->name = g_strdup(ifa->ifa_name);
829

    
830
            if (!cur_item) {
831
                head = cur_item = info;
832
            } else {
833
                cur_item->next = info;
834
                cur_item = info;
835
            }
836
        }
837

    
838
        if (!info->value->has_hardware_address &&
839
            ifa->ifa_flags & SIOCGIFHWADDR) {
840
            /* we haven't obtained HW address yet */
841
            sock = socket(PF_INET, SOCK_STREAM, 0);
842
            if (sock == -1) {
843
                error_setg_errno(errp, errno, "failed to create socket");
844
                goto error;
845
            }
846

    
847
            memset(&ifr, 0, sizeof(ifr));
848
            pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
849
            if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
850
                error_setg_errno(errp, errno,
851
                                 "failed to get MAC address of %s",
852
                                 ifa->ifa_name);
853
                goto error;
854
            }
855

    
856
            mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
857

    
858
            if (asprintf(&info->value->hardware_address,
859
                         "%02x:%02x:%02x:%02x:%02x:%02x",
860
                         (int) mac_addr[0], (int) mac_addr[1],
861
                         (int) mac_addr[2], (int) mac_addr[3],
862
                         (int) mac_addr[4], (int) mac_addr[5]) == -1) {
863
                error_setg_errno(errp, errno, "failed to format MAC");
864
                goto error;
865
            }
866

    
867
            info->value->has_hardware_address = true;
868
            close(sock);
869
        }
870

    
871
        if (ifa->ifa_addr &&
872
            ifa->ifa_addr->sa_family == AF_INET) {
873
            /* interface with IPv4 address */
874
            address_item = g_malloc0(sizeof(*address_item));
875
            address_item->value = g_malloc0(sizeof(*address_item->value));
876
            p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
877
            if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
878
                error_setg_errno(errp, errno, "inet_ntop failed");
879
                goto error;
880
            }
881

    
882
            address_item->value->ip_address = g_strdup(addr4);
883
            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
884

    
885
            if (ifa->ifa_netmask) {
886
                /* Count the number of set bits in netmask.
887
                 * This is safe as '1' and '0' cannot be shuffled in netmask. */
888
                p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
889
                address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
890
            }
891
        } else if (ifa->ifa_addr &&
892
                   ifa->ifa_addr->sa_family == AF_INET6) {
893
            /* interface with IPv6 address */
894
            address_item = g_malloc0(sizeof(*address_item));
895
            address_item->value = g_malloc0(sizeof(*address_item->value));
896
            p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
897
            if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
898
                error_setg_errno(errp, errno, "inet_ntop failed");
899
                goto error;
900
            }
901

    
902
            address_item->value->ip_address = g_strdup(addr6);
903
            address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
904

    
905
            if (ifa->ifa_netmask) {
906
                /* Count the number of set bits in netmask.
907
                 * This is safe as '1' and '0' cannot be shuffled in netmask. */
908
                p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
909
                address_item->value->prefix =
910
                    ctpop32(((uint32_t *) p)[0]) +
911
                    ctpop32(((uint32_t *) p)[1]) +
912
                    ctpop32(((uint32_t *) p)[2]) +
913
                    ctpop32(((uint32_t *) p)[3]);
914
            }
915
        }
916

    
917
        if (!address_item) {
918
            continue;
919
        }
920

    
921
        address_list = &info->value->ip_addresses;
922

    
923
        while (*address_list && (*address_list)->next) {
924
            address_list = &(*address_list)->next;
925
        }
926

    
927
        if (!*address_list) {
928
            *address_list = address_item;
929
        } else {
930
            (*address_list)->next = address_item;
931
        }
932

    
933
        info->value->has_ip_addresses = true;
934

    
935

    
936
    }
937

    
938
    freeifaddrs(ifap);
939
    return head;
940

    
941
error:
942
    freeifaddrs(ifap);
943
    qapi_free_GuestNetworkInterfaceList(head);
944
    return NULL;
945
}
946

    
947
#else /* defined(__linux__) */
948

    
949
void qmp_guest_suspend_disk(Error **err)
950
{
951
    error_set(err, QERR_UNSUPPORTED);
952
}
953

    
954
void qmp_guest_suspend_ram(Error **err)
955
{
956
    error_set(err, QERR_UNSUPPORTED);
957
}
958

    
959
void qmp_guest_suspend_hybrid(Error **err)
960
{
961
    error_set(err, QERR_UNSUPPORTED);
962
}
963

    
964
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
965
{
966
    error_set(errp, QERR_UNSUPPORTED);
967
    return NULL;
968
}
969

    
970
#endif
971

    
972
#if !defined(CONFIG_FSFREEZE)
973

    
974
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
975
{
976
    error_set(err, QERR_UNSUPPORTED);
977

    
978
    return 0;
979
}
980

    
981
int64_t qmp_guest_fsfreeze_freeze(Error **err)
982
{
983
    error_set(err, QERR_UNSUPPORTED);
984

    
985
    return 0;
986
}
987

    
988
int64_t qmp_guest_fsfreeze_thaw(Error **err)
989
{
990
    error_set(err, QERR_UNSUPPORTED);
991

    
992
    return 0;
993
}
994
#endif /* CONFIG_FSFREEZE */
995

    
996
#if !defined(CONFIG_FSTRIM)
997
void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
998
{
999
    error_set(err, QERR_UNSUPPORTED);
1000
}
1001
#endif
1002

    
1003
/* register init/cleanup routines for stateful command groups */
1004
void ga_command_state_init(GAState *s, GACommandState *cs)
1005
{
1006
#if defined(CONFIG_FSFREEZE)
1007
    ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
1008
#endif
1009
    ga_command_state_add(cs, guest_file_init, NULL);
1010
}