Annotation of qemu/qga/commands-posix.c, revision 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.