Annotation of qemu/qga/commands-posix.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU Guest Agent POSIX-specific command implementations
                      3:  *
                      4:  * Copyright IBM Corp. 2011
                      5:  *
                      6:  * Authors:
                      7:  *  Michael Roth      <[email protected]>
                      8:  *  Michal Privoznik  <[email protected]>
                      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 "qerror.h"
                     21: #include "qemu-queue.h"
                     22: #include "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: #if defined(__linux__) && defined(FIFREEZE)
                     42: #define CONFIG_FSFREEZE
                     43: #endif
                     44: #endif
                     45: 
                     46: void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
                     47: {
                     48:     const char *shutdown_flag;
                     49:     pid_t rpid, pid;
                     50:     int status;
                     51: 
                     52:     slog("guest-shutdown called, mode: %s", mode);
                     53:     if (!has_mode || strcmp(mode, "powerdown") == 0) {
                     54:         shutdown_flag = "-P";
                     55:     } else if (strcmp(mode, "halt") == 0) {
                     56:         shutdown_flag = "-H";
                     57:     } else if (strcmp(mode, "reboot") == 0) {
                     58:         shutdown_flag = "-r";
                     59:     } else {
                     60:         error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
                     61:                   "halt|powerdown|reboot");
                     62:         return;
                     63:     }
                     64: 
                     65:     pid = fork();
                     66:     if (pid == 0) {
                     67:         /* child, start the shutdown */
                     68:         setsid();
                     69:         reopen_fd_to_null(0);
                     70:         reopen_fd_to_null(1);
                     71:         reopen_fd_to_null(2);
                     72: 
                     73:         execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
                     74:                "hypervisor initiated shutdown", (char*)NULL, environ);
                     75:         _exit(EXIT_FAILURE);
                     76:     } else if (pid < 0) {
                     77:         goto exit_err;
                     78:     }
                     79: 
                     80:     do {
                     81:         rpid = waitpid(pid, &status, 0);
                     82:     } while (rpid == -1 && errno == EINTR);
                     83:     if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
                     84:         return;
                     85:     }
                     86: 
                     87: exit_err:
                     88:     error_set(err, QERR_UNDEFINED_ERROR);
                     89: }
                     90: 
                     91: typedef struct GuestFileHandle {
                     92:     uint64_t id;
                     93:     FILE *fh;
                     94:     QTAILQ_ENTRY(GuestFileHandle) next;
                     95: } GuestFileHandle;
                     96: 
                     97: static struct {
                     98:     QTAILQ_HEAD(, GuestFileHandle) filehandles;
                     99: } guest_file_state;
                    100: 
                    101: static void guest_file_handle_add(FILE *fh)
                    102: {
                    103:     GuestFileHandle *gfh;
                    104: 
                    105:     gfh = g_malloc0(sizeof(GuestFileHandle));
                    106:     gfh->id = fileno(fh);
                    107:     gfh->fh = fh;
                    108:     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
                    109: }
                    110: 
                    111: static GuestFileHandle *guest_file_handle_find(int64_t id)
                    112: {
                    113:     GuestFileHandle *gfh;
                    114: 
                    115:     QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
                    116:     {
                    117:         if (gfh->id == id) {
                    118:             return gfh;
                    119:         }
                    120:     }
                    121: 
                    122:     return NULL;
                    123: }
                    124: 
                    125: int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
                    126: {
                    127:     FILE *fh;
                    128:     int fd;
                    129:     int64_t ret = -1;
                    130: 
                    131:     if (!has_mode) {
                    132:         mode = "r";
                    133:     }
                    134:     slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
                    135:     fh = fopen(path, mode);
                    136:     if (!fh) {
                    137:         error_set(err, QERR_OPEN_FILE_FAILED, path);
                    138:         return -1;
                    139:     }
                    140: 
                    141:     /* set fd non-blocking to avoid common use cases (like reading from a
                    142:      * named pipe) from hanging the agent
                    143:      */
                    144:     fd = fileno(fh);
                    145:     ret = fcntl(fd, F_GETFL);
                    146:     ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
                    147:     if (ret == -1) {
                    148:         error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
                    149:         fclose(fh);
                    150:         return -1;
                    151:     }
                    152: 
                    153:     guest_file_handle_add(fh);
                    154:     slog("guest-file-open, handle: %d", fd);
                    155:     return fd;
                    156: }
                    157: 
                    158: void qmp_guest_file_close(int64_t handle, Error **err)
                    159: {
                    160:     GuestFileHandle *gfh = guest_file_handle_find(handle);
                    161:     int ret;
                    162: 
                    163:     slog("guest-file-close called, handle: %ld", handle);
                    164:     if (!gfh) {
                    165:         error_set(err, QERR_FD_NOT_FOUND, "handle");
                    166:         return;
                    167:     }
                    168: 
                    169:     ret = fclose(gfh->fh);
                    170:     if (ret == -1) {
                    171:         error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
                    172:         return;
                    173:     }
                    174: 
                    175:     QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
                    176:     g_free(gfh);
                    177: }
                    178: 
                    179: struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
                    180:                                           int64_t count, Error **err)
                    181: {
                    182:     GuestFileHandle *gfh = guest_file_handle_find(handle);
                    183:     GuestFileRead *read_data = NULL;
                    184:     guchar *buf;
                    185:     FILE *fh;
                    186:     size_t read_count;
                    187: 
                    188:     if (!gfh) {
                    189:         error_set(err, QERR_FD_NOT_FOUND, "handle");
                    190:         return NULL;
                    191:     }
                    192: 
                    193:     if (!has_count) {
                    194:         count = QGA_READ_COUNT_DEFAULT;
                    195:     } else if (count < 0) {
                    196:         error_set(err, QERR_INVALID_PARAMETER, "count");
                    197:         return NULL;
                    198:     }
                    199: 
                    200:     fh = gfh->fh;
                    201:     buf = g_malloc0(count+1);
                    202:     read_count = fread(buf, 1, count, fh);
                    203:     if (ferror(fh)) {
                    204:         slog("guest-file-read failed, handle: %ld", handle);
                    205:         error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
                    206:     } else {
                    207:         buf[read_count] = 0;
                    208:         read_data = g_malloc0(sizeof(GuestFileRead));
                    209:         read_data->count = read_count;
                    210:         read_data->eof = feof(fh);
                    211:         if (read_count) {
                    212:             read_data->buf_b64 = g_base64_encode(buf, read_count);
                    213:         }
                    214:     }
                    215:     g_free(buf);
                    216:     clearerr(fh);
                    217: 
                    218:     return read_data;
                    219: }
                    220: 
                    221: GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
                    222:                                      bool has_count, int64_t count, Error **err)
                    223: {
                    224:     GuestFileWrite *write_data = NULL;
                    225:     guchar *buf;
                    226:     gsize buf_len;
                    227:     int write_count;
                    228:     GuestFileHandle *gfh = guest_file_handle_find(handle);
                    229:     FILE *fh;
                    230: 
                    231:     if (!gfh) {
                    232:         error_set(err, QERR_FD_NOT_FOUND, "handle");
                    233:         return NULL;
                    234:     }
                    235: 
                    236:     fh = gfh->fh;
                    237:     buf = g_base64_decode(buf_b64, &buf_len);
                    238: 
                    239:     if (!has_count) {
                    240:         count = buf_len;
                    241:     } else if (count < 0 || count > buf_len) {
                    242:         g_free(buf);
                    243:         error_set(err, QERR_INVALID_PARAMETER, "count");
                    244:         return NULL;
                    245:     }
                    246: 
                    247:     write_count = fwrite(buf, 1, count, fh);
                    248:     if (ferror(fh)) {
                    249:         slog("guest-file-write failed, handle: %ld", handle);
                    250:         error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
                    251:     } else {
                    252:         write_data = g_malloc0(sizeof(GuestFileWrite));
                    253:         write_data->count = write_count;
                    254:         write_data->eof = feof(fh);
                    255:     }
                    256:     g_free(buf);
                    257:     clearerr(fh);
                    258: 
                    259:     return write_data;
                    260: }
                    261: 
                    262: struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
                    263:                                           int64_t whence, Error **err)
                    264: {
                    265:     GuestFileHandle *gfh = guest_file_handle_find(handle);
                    266:     GuestFileSeek *seek_data = NULL;
                    267:     FILE *fh;
                    268:     int ret;
                    269: 
                    270:     if (!gfh) {
                    271:         error_set(err, QERR_FD_NOT_FOUND, "handle");
                    272:         return NULL;
                    273:     }
                    274: 
                    275:     fh = gfh->fh;
                    276:     ret = fseek(fh, offset, whence);
                    277:     if (ret == -1) {
                    278:         error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
                    279:     } else {
                    280:         seek_data = g_malloc0(sizeof(GuestFileRead));
                    281:         seek_data->position = ftell(fh);
                    282:         seek_data->eof = feof(fh);
                    283:     }
                    284:     clearerr(fh);
                    285: 
                    286:     return seek_data;
                    287: }
                    288: 
                    289: void qmp_guest_file_flush(int64_t handle, Error **err)
                    290: {
                    291:     GuestFileHandle *gfh = guest_file_handle_find(handle);
                    292:     FILE *fh;
                    293:     int ret;
                    294: 
                    295:     if (!gfh) {
                    296:         error_set(err, QERR_FD_NOT_FOUND, "handle");
                    297:         return;
                    298:     }
                    299: 
                    300:     fh = gfh->fh;
                    301:     ret = fflush(fh);
                    302:     if (ret == EOF) {
                    303:         error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
                    304:     }
                    305: }
                    306: 
                    307: static void guest_file_init(void)
                    308: {
                    309:     QTAILQ_INIT(&guest_file_state.filehandles);
                    310: }
                    311: 
                    312: /* linux-specific implementations. avoid this if at all possible. */
                    313: #if defined(__linux__)
                    314: 
                    315: #if defined(CONFIG_FSFREEZE)
                    316: 
                    317: typedef struct GuestFsfreezeMount {
                    318:     char *dirname;
                    319:     char *devtype;
                    320:     QTAILQ_ENTRY(GuestFsfreezeMount) next;
                    321: } GuestFsfreezeMount;
                    322: 
                    323: typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
                    324: 
                    325: static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
                    326: {
                    327:      GuestFsfreezeMount *mount, *temp;
                    328: 
                    329:      if (!mounts) {
                    330:          return;
                    331:      }
                    332: 
                    333:      QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
                    334:          QTAILQ_REMOVE(mounts, mount, next);
                    335:          g_free(mount->dirname);
                    336:          g_free(mount->devtype);
                    337:          g_free(mount);
                    338:      }
                    339: }
                    340: 
                    341: /*
                    342:  * Walk the mount table and build a list of local file systems
                    343:  */
                    344: static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
                    345: {
                    346:     struct mntent *ment;
                    347:     GuestFsfreezeMount *mount;
                    348:     char const *mtab = "/proc/self/mounts";
                    349:     FILE *fp;
                    350: 
                    351:     fp = setmntent(mtab, "r");
                    352:     if (!fp) {
                    353:         g_warning("fsfreeze: unable to read mtab");
                    354:         return -1;
                    355:     }
                    356: 
                    357:     while ((ment = getmntent(fp))) {
                    358:         /*
                    359:          * An entry which device name doesn't start with a '/' is
                    360:          * either a dummy file system or a network file system.
                    361:          * Add special handling for smbfs and cifs as is done by
                    362:          * coreutils as well.
                    363:          */
                    364:         if ((ment->mnt_fsname[0] != '/') ||
                    365:             (strcmp(ment->mnt_type, "smbfs") == 0) ||
                    366:             (strcmp(ment->mnt_type, "cifs") == 0)) {
                    367:             continue;
                    368:         }
                    369: 
                    370:         mount = g_malloc0(sizeof(GuestFsfreezeMount));
                    371:         mount->dirname = g_strdup(ment->mnt_dir);
                    372:         mount->devtype = g_strdup(ment->mnt_type);
                    373: 
                    374:         QTAILQ_INSERT_TAIL(mounts, mount, next);
                    375:     }
                    376: 
                    377:     endmntent(fp);
                    378: 
                    379:     return 0;
                    380: }
                    381: 
                    382: /*
                    383:  * Return status of freeze/thaw
                    384:  */
                    385: GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
                    386: {
                    387:     if (ga_is_frozen(ga_state)) {
                    388:         return GUEST_FSFREEZE_STATUS_FROZEN;
                    389:     }
                    390: 
                    391:     return GUEST_FSFREEZE_STATUS_THAWED;
                    392: }
                    393: 
                    394: /*
                    395:  * Walk list of mounted file systems in the guest, and freeze the ones which
                    396:  * are real local file systems.
                    397:  */
                    398: int64_t qmp_guest_fsfreeze_freeze(Error **err)
                    399: {
                    400:     int ret = 0, i = 0;
                    401:     GuestFsfreezeMountList mounts;
                    402:     struct GuestFsfreezeMount *mount;
                    403:     int fd;
                    404:     char err_msg[512];
                    405: 
                    406:     slog("guest-fsfreeze called");
                    407: 
                    408:     QTAILQ_INIT(&mounts);
                    409:     ret = guest_fsfreeze_build_mount_list(&mounts);
                    410:     if (ret < 0) {
                    411:         return ret;
                    412:     }
                    413: 
                    414:     /* cannot risk guest agent blocking itself on a write in this state */
                    415:     ga_set_frozen(ga_state);
                    416: 
                    417:     QTAILQ_FOREACH(mount, &mounts, next) {
                    418:         fd = qemu_open(mount->dirname, O_RDONLY);
                    419:         if (fd == -1) {
                    420:             sprintf(err_msg, "failed to open %s, %s", mount->dirname,
                    421:                     strerror(errno));
                    422:             error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
                    423:             goto error;
                    424:         }
                    425: 
                    426:         /* we try to cull filesytems we know won't work in advance, but other
                    427:          * filesytems may not implement fsfreeze for less obvious reasons.
                    428:          * these will report EOPNOTSUPP. we simply ignore these when tallying
                    429:          * the number of frozen filesystems.
                    430:          *
                    431:          * any other error means a failure to freeze a filesystem we
                    432:          * expect to be freezable, so return an error in those cases
                    433:          * and return system to thawed state.
                    434:          */
                    435:         ret = ioctl(fd, FIFREEZE);
                    436:         if (ret == -1) {
                    437:             if (errno != EOPNOTSUPP) {
                    438:                 sprintf(err_msg, "failed to freeze %s, %s",
                    439:                         mount->dirname, strerror(errno));
                    440:                 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
                    441:                 close(fd);
                    442:                 goto error;
                    443:             }
                    444:         } else {
                    445:             i++;
                    446:         }
                    447:         close(fd);
                    448:     }
                    449: 
                    450:     guest_fsfreeze_free_mount_list(&mounts);
                    451:     return i;
                    452: 
                    453: error:
                    454:     guest_fsfreeze_free_mount_list(&mounts);
                    455:     qmp_guest_fsfreeze_thaw(NULL);
                    456:     return 0;
                    457: }
                    458: 
                    459: /*
                    460:  * Walk list of frozen file systems in the guest, and thaw them.
                    461:  */
                    462: int64_t qmp_guest_fsfreeze_thaw(Error **err)
                    463: {
                    464:     int ret;
                    465:     GuestFsfreezeMountList mounts;
                    466:     GuestFsfreezeMount *mount;
                    467:     int fd, i = 0, logged;
                    468: 
                    469:     QTAILQ_INIT(&mounts);
                    470:     ret = guest_fsfreeze_build_mount_list(&mounts);
                    471:     if (ret) {
                    472:         error_set(err, QERR_QGA_COMMAND_FAILED,
                    473:                   "failed to enumerate filesystems");
                    474:         return 0;
                    475:     }
                    476: 
                    477:     QTAILQ_FOREACH(mount, &mounts, next) {
                    478:         logged = false;
                    479:         fd = qemu_open(mount->dirname, O_RDONLY);
                    480:         if (fd == -1) {
                    481:             continue;
                    482:         }
                    483:         /* we have no way of knowing whether a filesystem was actually unfrozen
                    484:          * as a result of a successful call to FITHAW, only that if an error
                    485:          * was returned the filesystem was *not* unfrozen by that particular
                    486:          * call.
                    487:          *
                    488:          * since multiple preceding FIFREEZEs require multiple calls to FITHAW
                    489:          * to unfreeze, continuing issuing FITHAW until an error is returned,
                    490:          * in which case either the filesystem is in an unfreezable state, or,
                    491:          * more likely, it was thawed previously (and remains so afterward).
                    492:          *
                    493:          * also, since the most recent successful call is the one that did
                    494:          * the actual unfreeze, we can use this to provide an accurate count
                    495:          * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
                    496:          * may * be useful for determining whether a filesystem was unfrozen
                    497:          * during the freeze/thaw phase by a process other than qemu-ga.
                    498:          */
                    499:         do {
                    500:             ret = ioctl(fd, FITHAW);
                    501:             if (ret == 0 && !logged) {
                    502:                 i++;
                    503:                 logged = true;
                    504:             }
                    505:         } while (ret == 0);
                    506:         close(fd);
                    507:     }
                    508: 
                    509:     ga_unset_frozen(ga_state);
                    510:     guest_fsfreeze_free_mount_list(&mounts);
                    511:     return i;
                    512: }
                    513: 
                    514: static void guest_fsfreeze_cleanup(void)
                    515: {
                    516:     int64_t ret;
                    517:     Error *err = NULL;
                    518: 
                    519:     if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
                    520:         ret = qmp_guest_fsfreeze_thaw(&err);
                    521:         if (ret < 0 || err) {
                    522:             slog("failed to clean up frozen filesystems");
                    523:         }
                    524:     }
                    525: }
                    526: #endif /* CONFIG_FSFREEZE */
                    527: 
                    528: #define LINUX_SYS_STATE_FILE "/sys/power/state"
                    529: #define SUSPEND_SUPPORTED 0
                    530: #define SUSPEND_NOT_SUPPORTED 1
                    531: 
                    532: static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
                    533:                                const char *sysfile_str, Error **err)
                    534: {
                    535:     char *pmutils_path;
                    536:     pid_t pid, rpid;
                    537:     int status;
                    538: 
                    539:     pmutils_path = g_find_program_in_path(pmutils_bin);
                    540: 
                    541:     pid = fork();
                    542:     if (!pid) {
                    543:         char buf[32]; /* hopefully big enough */
                    544:         ssize_t ret;
                    545:         int fd;
                    546: 
                    547:         setsid();
                    548:         reopen_fd_to_null(0);
                    549:         reopen_fd_to_null(1);
                    550:         reopen_fd_to_null(2);
                    551: 
                    552:         if (pmutils_path) {
                    553:             execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
                    554:         }
                    555: 
                    556:         /*
                    557:          * If we get here either pm-utils is not installed or execle() has
                    558:          * failed. Let's try the manual method if the caller wants it.
                    559:          */
                    560: 
                    561:         if (!sysfile_str) {
                    562:             _exit(SUSPEND_NOT_SUPPORTED);
                    563:         }
                    564: 
                    565:         fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
                    566:         if (fd < 0) {
                    567:             _exit(SUSPEND_NOT_SUPPORTED);
                    568:         }
                    569: 
                    570:         ret = read(fd, buf, sizeof(buf)-1);
                    571:         if (ret <= 0) {
                    572:             _exit(SUSPEND_NOT_SUPPORTED);
                    573:         }
                    574:         buf[ret] = '\0';
                    575: 
                    576:         if (strstr(buf, sysfile_str)) {
                    577:             _exit(SUSPEND_SUPPORTED);
                    578:         }
                    579: 
                    580:         _exit(SUSPEND_NOT_SUPPORTED);
                    581:     }
                    582: 
                    583:     g_free(pmutils_path);
                    584: 
                    585:     if (pid < 0) {
                    586:         goto undef_err;
                    587:     }
                    588: 
                    589:     do {
                    590:         rpid = waitpid(pid, &status, 0);
                    591:     } while (rpid == -1 && errno == EINTR);
                    592:     if (rpid == pid && WIFEXITED(status)) {
                    593:         switch (WEXITSTATUS(status)) {
                    594:         case SUSPEND_SUPPORTED:
                    595:             return;
                    596:         case SUSPEND_NOT_SUPPORTED:
                    597:             error_set(err, QERR_UNSUPPORTED);
                    598:             return;
                    599:         default:
                    600:             goto undef_err;
                    601:         }
                    602:     }
                    603: 
                    604: undef_err:
                    605:     error_set(err, QERR_UNDEFINED_ERROR);
                    606: }
                    607: 
                    608: static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
                    609:                           Error **err)
                    610: {
                    611:     char *pmutils_path;
                    612:     pid_t rpid, pid;
                    613:     int status;
                    614: 
                    615:     pmutils_path = g_find_program_in_path(pmutils_bin);
                    616: 
                    617:     pid = fork();
                    618:     if (pid == 0) {
                    619:         /* child */
                    620:         int fd;
                    621: 
                    622:         setsid();
                    623:         reopen_fd_to_null(0);
                    624:         reopen_fd_to_null(1);
                    625:         reopen_fd_to_null(2);
                    626: 
                    627:         if (pmutils_path) {
                    628:             execle(pmutils_path, pmutils_bin, NULL, environ);
                    629:         }
                    630: 
                    631:         /*
                    632:          * If we get here either pm-utils is not installed or execle() has
                    633:          * failed. Let's try the manual method if the caller wants it.
                    634:          */
                    635: 
                    636:         if (!sysfile_str) {
                    637:             _exit(EXIT_FAILURE);
                    638:         }
                    639: 
                    640:         fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
                    641:         if (fd < 0) {
                    642:             _exit(EXIT_FAILURE);
                    643:         }
                    644: 
                    645:         if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
                    646:             _exit(EXIT_FAILURE);
                    647:         }
                    648: 
                    649:         _exit(EXIT_SUCCESS);
                    650:     }
                    651: 
                    652:     g_free(pmutils_path);
                    653: 
                    654:     if (pid < 0) {
                    655:         goto exit_err;
                    656:     }
                    657: 
                    658:     do {
                    659:         rpid = waitpid(pid, &status, 0);
                    660:     } while (rpid == -1 && errno == EINTR);
                    661:     if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
                    662:         return;
                    663:     }
                    664: 
                    665: exit_err:
                    666:     error_set(err, QERR_UNDEFINED_ERROR);
                    667: }
                    668: 
                    669: void qmp_guest_suspend_disk(Error **err)
                    670: {
                    671:     bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
                    672:     if (error_is_set(err)) {
                    673:         return;
                    674:     }
                    675: 
                    676:     guest_suspend("pm-hibernate", "disk", err);
                    677: }
                    678: 
                    679: void qmp_guest_suspend_ram(Error **err)
                    680: {
                    681:     bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
                    682:     if (error_is_set(err)) {
                    683:         return;
                    684:     }
                    685: 
                    686:     guest_suspend("pm-suspend", "mem", err);
                    687: }
                    688: 
                    689: void qmp_guest_suspend_hybrid(Error **err)
                    690: {
                    691:     bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
                    692:     if (error_is_set(err)) {
                    693:         return;
                    694:     }
                    695: 
                    696:     guest_suspend("pm-suspend-hybrid", NULL, err);
                    697: }
                    698: 
                    699: static GuestNetworkInterfaceList *
                    700: guest_find_interface(GuestNetworkInterfaceList *head,
                    701:                      const char *name)
                    702: {
                    703:     for (; head; head = head->next) {
                    704:         if (strcmp(head->value->name, name) == 0) {
                    705:             break;
                    706:         }
                    707:     }
                    708: 
                    709:     return head;
                    710: }
                    711: 
                    712: /*
                    713:  * Build information about guest interfaces
                    714:  */
                    715: GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
                    716: {
                    717:     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
                    718:     struct ifaddrs *ifap, *ifa;
                    719:     char err_msg[512];
                    720: 
                    721:     if (getifaddrs(&ifap) < 0) {
                    722:         snprintf(err_msg, sizeof(err_msg),
                    723:                  "getifaddrs failed: %s", strerror(errno));
                    724:         error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    725:         goto error;
                    726:     }
                    727: 
                    728:     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
                    729:         GuestNetworkInterfaceList *info;
                    730:         GuestIpAddressList **address_list = NULL, *address_item = NULL;
                    731:         char addr4[INET_ADDRSTRLEN];
                    732:         char addr6[INET6_ADDRSTRLEN];
                    733:         int sock;
                    734:         struct ifreq ifr;
                    735:         unsigned char *mac_addr;
                    736:         void *p;
                    737: 
                    738:         g_debug("Processing %s interface", ifa->ifa_name);
                    739: 
                    740:         info = guest_find_interface(head, ifa->ifa_name);
                    741: 
                    742:         if (!info) {
                    743:             info = g_malloc0(sizeof(*info));
                    744:             info->value = g_malloc0(sizeof(*info->value));
                    745:             info->value->name = g_strdup(ifa->ifa_name);
                    746: 
                    747:             if (!cur_item) {
                    748:                 head = cur_item = info;
                    749:             } else {
                    750:                 cur_item->next = info;
                    751:                 cur_item = info;
                    752:             }
                    753:         }
                    754: 
                    755:         if (!info->value->has_hardware_address &&
                    756:             ifa->ifa_flags & SIOCGIFHWADDR) {
                    757:             /* we haven't obtained HW address yet */
                    758:             sock = socket(PF_INET, SOCK_STREAM, 0);
                    759:             if (sock == -1) {
                    760:                 snprintf(err_msg, sizeof(err_msg),
                    761:                          "failed to create socket: %s", strerror(errno));
                    762:                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    763:                 goto error;
                    764:             }
                    765: 
                    766:             memset(&ifr, 0, sizeof(ifr));
                    767:             strncpy(ifr.ifr_name,  info->value->name, IF_NAMESIZE);
                    768:             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
                    769:                 snprintf(err_msg, sizeof(err_msg),
                    770:                          "failed to get MAC address of %s: %s",
                    771:                          ifa->ifa_name,
                    772:                          strerror(errno));
                    773:                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    774:                 goto error;
                    775:             }
                    776: 
                    777:             mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
                    778: 
                    779:             if (asprintf(&info->value->hardware_address,
                    780:                          "%02x:%02x:%02x:%02x:%02x:%02x",
                    781:                          (int) mac_addr[0], (int) mac_addr[1],
                    782:                          (int) mac_addr[2], (int) mac_addr[3],
                    783:                          (int) mac_addr[4], (int) mac_addr[5]) == -1) {
                    784:                 snprintf(err_msg, sizeof(err_msg),
                    785:                          "failed to format MAC: %s", strerror(errno));
                    786:                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    787:                 goto error;
                    788:             }
                    789: 
                    790:             info->value->has_hardware_address = true;
                    791:             close(sock);
                    792:         }
                    793: 
                    794:         if (ifa->ifa_addr &&
                    795:             ifa->ifa_addr->sa_family == AF_INET) {
                    796:             /* interface with IPv4 address */
                    797:             address_item = g_malloc0(sizeof(*address_item));
                    798:             address_item->value = g_malloc0(sizeof(*address_item->value));
                    799:             p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
                    800:             if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
                    801:                 snprintf(err_msg, sizeof(err_msg),
                    802:                          "inet_ntop failed : %s", strerror(errno));
                    803:                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    804:                 goto error;
                    805:             }
                    806: 
                    807:             address_item->value->ip_address = g_strdup(addr4);
                    808:             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
                    809: 
                    810:             if (ifa->ifa_netmask) {
                    811:                 /* Count the number of set bits in netmask.
                    812:                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
                    813:                 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
                    814:                 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
                    815:             }
                    816:         } else if (ifa->ifa_addr &&
                    817:                    ifa->ifa_addr->sa_family == AF_INET6) {
                    818:             /* interface with IPv6 address */
                    819:             address_item = g_malloc0(sizeof(*address_item));
                    820:             address_item->value = g_malloc0(sizeof(*address_item->value));
                    821:             p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
                    822:             if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
                    823:                 snprintf(err_msg, sizeof(err_msg),
                    824:                          "inet_ntop failed : %s", strerror(errno));
                    825:                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
                    826:                 goto error;
                    827:             }
                    828: 
                    829:             address_item->value->ip_address = g_strdup(addr6);
                    830:             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
                    831: 
                    832:             if (ifa->ifa_netmask) {
                    833:                 /* Count the number of set bits in netmask.
                    834:                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
                    835:                 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
                    836:                 address_item->value->prefix =
                    837:                     ctpop32(((uint32_t *) p)[0]) +
                    838:                     ctpop32(((uint32_t *) p)[1]) +
                    839:                     ctpop32(((uint32_t *) p)[2]) +
                    840:                     ctpop32(((uint32_t *) p)[3]);
                    841:             }
                    842:         }
                    843: 
                    844:         if (!address_item) {
                    845:             continue;
                    846:         }
                    847: 
                    848:         address_list = &info->value->ip_addresses;
                    849: 
                    850:         while (*address_list && (*address_list)->next) {
                    851:             address_list = &(*address_list)->next;
                    852:         }
                    853: 
                    854:         if (!*address_list) {
                    855:             *address_list = address_item;
                    856:         } else {
                    857:             (*address_list)->next = address_item;
                    858:         }
                    859: 
                    860:         info->value->has_ip_addresses = true;
                    861: 
                    862: 
                    863:     }
                    864: 
                    865:     freeifaddrs(ifap);
                    866:     return head;
                    867: 
                    868: error:
                    869:     freeifaddrs(ifap);
                    870:     qapi_free_GuestNetworkInterfaceList(head);
                    871:     return NULL;
                    872: }
                    873: 
                    874: #else /* defined(__linux__) */
                    875: 
                    876: void qmp_guest_suspend_disk(Error **err)
                    877: {
                    878:     error_set(err, QERR_UNSUPPORTED);
                    879: }
                    880: 
                    881: void qmp_guest_suspend_ram(Error **err)
                    882: {
                    883:     error_set(err, QERR_UNSUPPORTED);
                    884: }
                    885: 
                    886: void qmp_guest_suspend_hybrid(Error **err)
                    887: {
                    888:     error_set(err, QERR_UNSUPPORTED);
                    889: }
                    890: 
                    891: GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
                    892: {
                    893:     error_set(errp, QERR_UNSUPPORTED);
                    894:     return NULL;
                    895: }
                    896: 
                    897: #endif
                    898: 
                    899: #if !defined(CONFIG_FSFREEZE)
                    900: 
                    901: GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
                    902: {
                    903:     error_set(err, QERR_UNSUPPORTED);
                    904: 
                    905:     return 0;
                    906: }
                    907: 
                    908: int64_t qmp_guest_fsfreeze_freeze(Error **err)
                    909: {
                    910:     error_set(err, QERR_UNSUPPORTED);
                    911: 
                    912:     return 0;
                    913: }
                    914: 
                    915: int64_t qmp_guest_fsfreeze_thaw(Error **err)
                    916: {
                    917:     error_set(err, QERR_UNSUPPORTED);
                    918: 
                    919:     return 0;
                    920: }
                    921: 
                    922: #endif
                    923: 
                    924: /* register init/cleanup routines for stateful command groups */
                    925: void ga_command_state_init(GAState *s, GACommandState *cs)
                    926: {
                    927: #if defined(CONFIG_FSFREEZE)
                    928:     ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
                    929: #endif
                    930:     ga_command_state_add(cs, guest_file_init, NULL);
                    931: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.