142074a9dSMichael Roth /* 242074a9dSMichael Roth * QEMU Guest Agent common/cross-platform command implementations 342074a9dSMichael Roth * 442074a9dSMichael Roth * Copyright IBM Corp. 2012 542074a9dSMichael Roth * 642074a9dSMichael Roth * Authors: 742074a9dSMichael Roth * Michael Roth <mdroth@linux.vnet.ibm.com> 842074a9dSMichael Roth * 942074a9dSMichael Roth * This work is licensed under the terms of the GNU GPL, version 2 or later. 1042074a9dSMichael Roth * See the COPYING file in the top-level directory. 1142074a9dSMichael Roth */ 1242074a9dSMichael Roth 134459bf38SPeter Maydell #include "qemu/osdep.h" 1442074a9dSMichael Roth #include "qga/guest-agent-core.h" 1542074a9dSMichael Roth #include "qga-qmp-commands.h" 167b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 17920639caSDaniel P. Berrange #include "qemu/base64.h" 18f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 19a31393e7SAlex Bennée #include "qemu/atomic.h" 2042074a9dSMichael Roth 21a1853dcaSYuri Pudgorodskiy /* Maximum captured guest-exec out_data/err_data - 16MB */ 22a1853dcaSYuri Pudgorodskiy #define GUEST_EXEC_MAX_OUTPUT (16*1024*1024) 23a1853dcaSYuri Pudgorodskiy /* Allocation and I/O buffer for reading guest-exec out_data/err_data - 4KB */ 24a1853dcaSYuri Pudgorodskiy #define GUEST_EXEC_IO_SIZE (4*1024) 25a1853dcaSYuri Pudgorodskiy 2642074a9dSMichael Roth /* Note: in some situations, like with the fsfreeze, logging may be 2742074a9dSMichael Roth * temporarilly disabled. if it is necessary that a command be able 2842074a9dSMichael Roth * to log for accounting purposes, check ga_logging_enabled() beforehand, 2942074a9dSMichael Roth * and use the QERR_QGA_LOGGING_DISABLED to generate an error 3042074a9dSMichael Roth */ 3142074a9dSMichael Roth void slog(const gchar *fmt, ...) 3242074a9dSMichael Roth { 3342074a9dSMichael Roth va_list ap; 3442074a9dSMichael Roth 3542074a9dSMichael Roth va_start(ap, fmt); 3642074a9dSMichael Roth g_logv("syslog", G_LOG_LEVEL_INFO, fmt, ap); 3742074a9dSMichael Roth va_end(ap); 3842074a9dSMichael Roth } 3942074a9dSMichael Roth 403cf0bed8SMichael Roth int64_t qmp_guest_sync_delimited(int64_t id, Error **errp) 413cf0bed8SMichael Roth { 423cf0bed8SMichael Roth ga_set_response_delimited(ga_state); 433cf0bed8SMichael Roth return id; 443cf0bed8SMichael Roth } 453cf0bed8SMichael Roth 4642074a9dSMichael Roth int64_t qmp_guest_sync(int64_t id, Error **errp) 4742074a9dSMichael Roth { 4842074a9dSMichael Roth return id; 4942074a9dSMichael Roth } 5042074a9dSMichael Roth 5177dbc81bSMarkus Armbruster void qmp_guest_ping(Error **errp) 5242074a9dSMichael Roth { 5342074a9dSMichael Roth slog("guest-ping called"); 5442074a9dSMichael Roth } 5542074a9dSMichael Roth 568dc4d915SMark Wu static void qmp_command_info(QmpCommand *cmd, void *opaque) 5742074a9dSMichael Roth { 588dc4d915SMark Wu GuestAgentInfo *info = opaque; 5942074a9dSMichael Roth GuestAgentCommandInfo *cmd_info; 6042074a9dSMichael Roth GuestAgentCommandInfoList *cmd_info_list; 6142074a9dSMichael Roth 62f3a06403SMarkus Armbruster cmd_info = g_new0(GuestAgentCommandInfo, 1); 638dc4d915SMark Wu cmd_info->name = g_strdup(qmp_command_name(cmd)); 648dc4d915SMark Wu cmd_info->enabled = qmp_command_is_enabled(cmd); 650106dc4fSMark Wu cmd_info->success_response = qmp_has_success_response(cmd); 6642074a9dSMichael Roth 67f3a06403SMarkus Armbruster cmd_info_list = g_new0(GuestAgentCommandInfoList, 1); 6842074a9dSMichael Roth cmd_info_list->value = cmd_info; 6942074a9dSMichael Roth cmd_info_list->next = info->supported_commands; 7042074a9dSMichael Roth info->supported_commands = cmd_info_list; 7142074a9dSMichael Roth } 7242074a9dSMichael Roth 7377dbc81bSMarkus Armbruster struct GuestAgentInfo *qmp_guest_info(Error **errp) 748dc4d915SMark Wu { 75f3a06403SMarkus Armbruster GuestAgentInfo *info = g_new0(GuestAgentInfo, 1); 768dc4d915SMark Wu 778dc4d915SMark Wu info->version = g_strdup(QEMU_VERSION); 781527badbSMarkus Armbruster qmp_for_each_command(&ga_commands, qmp_command_info, info); 7942074a9dSMichael Roth return info; 8042074a9dSMichael Roth } 81d697e30cSYuri Pudgorodskiy 82a1853dcaSYuri Pudgorodskiy struct GuestExecIOData { 83a1853dcaSYuri Pudgorodskiy guchar *data; 84a1853dcaSYuri Pudgorodskiy gsize size; 85a1853dcaSYuri Pudgorodskiy gsize length; 86a31393e7SAlex Bennée bool closed; 87a1853dcaSYuri Pudgorodskiy bool truncated; 88a1853dcaSYuri Pudgorodskiy const char *name; 89a1853dcaSYuri Pudgorodskiy }; 90a1853dcaSYuri Pudgorodskiy typedef struct GuestExecIOData GuestExecIOData; 91a1853dcaSYuri Pudgorodskiy 92d697e30cSYuri Pudgorodskiy struct GuestExecInfo { 93d697e30cSYuri Pudgorodskiy GPid pid; 94d697e30cSYuri Pudgorodskiy int64_t pid_numeric; 95d697e30cSYuri Pudgorodskiy gint status; 96a1853dcaSYuri Pudgorodskiy bool has_output; 97a31393e7SAlex Bennée bool finished; 98a1853dcaSYuri Pudgorodskiy GuestExecIOData in; 99a1853dcaSYuri Pudgorodskiy GuestExecIOData out; 100a1853dcaSYuri Pudgorodskiy GuestExecIOData err; 101d697e30cSYuri Pudgorodskiy QTAILQ_ENTRY(GuestExecInfo) next; 102d697e30cSYuri Pudgorodskiy }; 103d697e30cSYuri Pudgorodskiy typedef struct GuestExecInfo GuestExecInfo; 104d697e30cSYuri Pudgorodskiy 105d697e30cSYuri Pudgorodskiy static struct { 106d697e30cSYuri Pudgorodskiy QTAILQ_HEAD(, GuestExecInfo) processes; 107d697e30cSYuri Pudgorodskiy } guest_exec_state = { 108d697e30cSYuri Pudgorodskiy .processes = QTAILQ_HEAD_INITIALIZER(guest_exec_state.processes), 109d697e30cSYuri Pudgorodskiy }; 110d697e30cSYuri Pudgorodskiy 111d697e30cSYuri Pudgorodskiy static int64_t gpid_to_int64(GPid pid) 112d697e30cSYuri Pudgorodskiy { 113d697e30cSYuri Pudgorodskiy #ifdef G_OS_WIN32 114d697e30cSYuri Pudgorodskiy return GetProcessId(pid); 115d697e30cSYuri Pudgorodskiy #else 116d697e30cSYuri Pudgorodskiy return (int64_t)pid; 117d697e30cSYuri Pudgorodskiy #endif 118d697e30cSYuri Pudgorodskiy } 119d697e30cSYuri Pudgorodskiy 120d697e30cSYuri Pudgorodskiy static GuestExecInfo *guest_exec_info_add(GPid pid) 121d697e30cSYuri Pudgorodskiy { 122d697e30cSYuri Pudgorodskiy GuestExecInfo *gei; 123d697e30cSYuri Pudgorodskiy 124d697e30cSYuri Pudgorodskiy gei = g_new0(GuestExecInfo, 1); 125d697e30cSYuri Pudgorodskiy gei->pid = pid; 126d697e30cSYuri Pudgorodskiy gei->pid_numeric = gpid_to_int64(pid); 127d697e30cSYuri Pudgorodskiy QTAILQ_INSERT_TAIL(&guest_exec_state.processes, gei, next); 128d697e30cSYuri Pudgorodskiy 129d697e30cSYuri Pudgorodskiy return gei; 130d697e30cSYuri Pudgorodskiy } 131d697e30cSYuri Pudgorodskiy 132d697e30cSYuri Pudgorodskiy static GuestExecInfo *guest_exec_info_find(int64_t pid_numeric) 133d697e30cSYuri Pudgorodskiy { 134d697e30cSYuri Pudgorodskiy GuestExecInfo *gei; 135d697e30cSYuri Pudgorodskiy 136d697e30cSYuri Pudgorodskiy QTAILQ_FOREACH(gei, &guest_exec_state.processes, next) { 137d697e30cSYuri Pudgorodskiy if (gei->pid_numeric == pid_numeric) { 138d697e30cSYuri Pudgorodskiy return gei; 139d697e30cSYuri Pudgorodskiy } 140d697e30cSYuri Pudgorodskiy } 141d697e30cSYuri Pudgorodskiy 142d697e30cSYuri Pudgorodskiy return NULL; 143d697e30cSYuri Pudgorodskiy } 144d697e30cSYuri Pudgorodskiy 145d697e30cSYuri Pudgorodskiy GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err) 146d697e30cSYuri Pudgorodskiy { 147d697e30cSYuri Pudgorodskiy GuestExecInfo *gei; 148d697e30cSYuri Pudgorodskiy GuestExecStatus *ges; 149d697e30cSYuri Pudgorodskiy 150d697e30cSYuri Pudgorodskiy slog("guest-exec-status called, pid: %u", (uint32_t)pid); 151d697e30cSYuri Pudgorodskiy 152d697e30cSYuri Pudgorodskiy gei = guest_exec_info_find(pid); 153d697e30cSYuri Pudgorodskiy if (gei == NULL) { 154d697e30cSYuri Pudgorodskiy error_setg(err, QERR_INVALID_PARAMETER, "pid"); 155d697e30cSYuri Pudgorodskiy return NULL; 156d697e30cSYuri Pudgorodskiy } 157d697e30cSYuri Pudgorodskiy 158d697e30cSYuri Pudgorodskiy ges = g_new0(GuestExecStatus, 1); 159d697e30cSYuri Pudgorodskiy 160a31393e7SAlex Bennée bool finished = atomic_mb_read(&gei->finished); 161a1853dcaSYuri Pudgorodskiy 162a1853dcaSYuri Pudgorodskiy /* need to wait till output channels are closed 163a1853dcaSYuri Pudgorodskiy * to be sure we captured all output at this point */ 164a1853dcaSYuri Pudgorodskiy if (gei->has_output) { 165a31393e7SAlex Bennée finished = finished && atomic_mb_read(&gei->out.closed); 166a31393e7SAlex Bennée finished = finished && atomic_mb_read(&gei->err.closed); 167a1853dcaSYuri Pudgorodskiy } 168a1853dcaSYuri Pudgorodskiy 169a1853dcaSYuri Pudgorodskiy ges->exited = finished; 170a1853dcaSYuri Pudgorodskiy if (finished) { 171d697e30cSYuri Pudgorodskiy /* Glib has no portable way to parse exit status. 172d697e30cSYuri Pudgorodskiy * On UNIX, we can get either exit code from normal termination 173d697e30cSYuri Pudgorodskiy * or signal number. 174d697e30cSYuri Pudgorodskiy * On Windows, it is either the same exit code or the exception 175d697e30cSYuri Pudgorodskiy * value for an unhandled exception that caused the process 176d697e30cSYuri Pudgorodskiy * to terminate. 177d697e30cSYuri Pudgorodskiy * See MSDN for GetExitCodeProcess() and ntstatus.h for possible 178d697e30cSYuri Pudgorodskiy * well-known codes, e.g. C0000005 ACCESS_DENIED - analog of SIGSEGV 179d697e30cSYuri Pudgorodskiy * References: 180d697e30cSYuri Pudgorodskiy * https://msdn.microsoft.com/en-us/library/windows/desktop/ms683189(v=vs.85).aspx 181d697e30cSYuri Pudgorodskiy * https://msdn.microsoft.com/en-us/library/aa260331(v=vs.60).aspx 182d697e30cSYuri Pudgorodskiy */ 183d697e30cSYuri Pudgorodskiy #ifdef G_OS_WIN32 184d697e30cSYuri Pudgorodskiy /* Additionally WIN32 does not provide any additional information 185d697e30cSYuri Pudgorodskiy * on whether the child exited or terminated via signal. 186cb8d4c8fSStefan Weil * We use this simple range check to distinguish application exit code 187d697e30cSYuri Pudgorodskiy * (usually value less then 256) and unhandled exception code with 188d697e30cSYuri Pudgorodskiy * ntstatus (always value greater then 0xC0000005). */ 189d697e30cSYuri Pudgorodskiy if ((uint32_t)gei->status < 0xC0000000U) { 190d697e30cSYuri Pudgorodskiy ges->has_exitcode = true; 191d697e30cSYuri Pudgorodskiy ges->exitcode = gei->status; 192d697e30cSYuri Pudgorodskiy } else { 193d697e30cSYuri Pudgorodskiy ges->has_signal = true; 194d697e30cSYuri Pudgorodskiy ges->signal = gei->status; 195d697e30cSYuri Pudgorodskiy } 196d697e30cSYuri Pudgorodskiy #else 197d697e30cSYuri Pudgorodskiy if (WIFEXITED(gei->status)) { 198d697e30cSYuri Pudgorodskiy ges->has_exitcode = true; 199d697e30cSYuri Pudgorodskiy ges->exitcode = WEXITSTATUS(gei->status); 200d697e30cSYuri Pudgorodskiy } else if (WIFSIGNALED(gei->status)) { 201d697e30cSYuri Pudgorodskiy ges->has_signal = true; 202d697e30cSYuri Pudgorodskiy ges->signal = WTERMSIG(gei->status); 203d697e30cSYuri Pudgorodskiy } 204d697e30cSYuri Pudgorodskiy #endif 205a1853dcaSYuri Pudgorodskiy if (gei->out.length > 0) { 206a1853dcaSYuri Pudgorodskiy ges->has_out_data = true; 207a1853dcaSYuri Pudgorodskiy ges->out_data = g_base64_encode(gei->out.data, gei->out.length); 208a1853dcaSYuri Pudgorodskiy g_free(gei->out.data); 209a1853dcaSYuri Pudgorodskiy ges->has_out_truncated = gei->out.truncated; 210a1853dcaSYuri Pudgorodskiy } 211a1853dcaSYuri Pudgorodskiy 212a1853dcaSYuri Pudgorodskiy if (gei->err.length > 0) { 213a1853dcaSYuri Pudgorodskiy ges->has_err_data = true; 214a1853dcaSYuri Pudgorodskiy ges->err_data = g_base64_encode(gei->err.data, gei->err.length); 215a1853dcaSYuri Pudgorodskiy g_free(gei->err.data); 216a1853dcaSYuri Pudgorodskiy ges->has_err_truncated = gei->err.truncated; 217a1853dcaSYuri Pudgorodskiy } 218a1853dcaSYuri Pudgorodskiy 219d697e30cSYuri Pudgorodskiy QTAILQ_REMOVE(&guest_exec_state.processes, gei, next); 220d697e30cSYuri Pudgorodskiy g_free(gei); 221d697e30cSYuri Pudgorodskiy } 222d697e30cSYuri Pudgorodskiy 223d697e30cSYuri Pudgorodskiy return ges; 224d697e30cSYuri Pudgorodskiy } 225d697e30cSYuri Pudgorodskiy 226d697e30cSYuri Pudgorodskiy /* Get environment variables or arguments array for execve(). */ 227d697e30cSYuri Pudgorodskiy static char **guest_exec_get_args(const strList *entry, bool log) 228d697e30cSYuri Pudgorodskiy { 229d697e30cSYuri Pudgorodskiy const strList *it; 230d697e30cSYuri Pudgorodskiy int count = 1, i = 0; /* reserve for NULL terminator */ 231d697e30cSYuri Pudgorodskiy char **args; 232d697e30cSYuri Pudgorodskiy char *str; /* for logging array of arguments */ 233d697e30cSYuri Pudgorodskiy size_t str_size = 1; 234d697e30cSYuri Pudgorodskiy 235d697e30cSYuri Pudgorodskiy for (it = entry; it != NULL; it = it->next) { 236d697e30cSYuri Pudgorodskiy count++; 237d697e30cSYuri Pudgorodskiy str_size += 1 + strlen(it->value); 238d697e30cSYuri Pudgorodskiy } 239d697e30cSYuri Pudgorodskiy 240d697e30cSYuri Pudgorodskiy str = g_malloc(str_size); 241d697e30cSYuri Pudgorodskiy *str = 0; 242d697e30cSYuri Pudgorodskiy args = g_malloc(count * sizeof(char *)); 243d697e30cSYuri Pudgorodskiy for (it = entry; it != NULL; it = it->next) { 244d697e30cSYuri Pudgorodskiy args[i++] = it->value; 245d697e30cSYuri Pudgorodskiy pstrcat(str, str_size, it->value); 246d697e30cSYuri Pudgorodskiy if (it->next) { 247d697e30cSYuri Pudgorodskiy pstrcat(str, str_size, " "); 248d697e30cSYuri Pudgorodskiy } 249d697e30cSYuri Pudgorodskiy } 250d697e30cSYuri Pudgorodskiy args[i] = NULL; 251d697e30cSYuri Pudgorodskiy 252d697e30cSYuri Pudgorodskiy if (log) { 253d697e30cSYuri Pudgorodskiy slog("guest-exec called: \"%s\"", str); 254d697e30cSYuri Pudgorodskiy } 255d697e30cSYuri Pudgorodskiy g_free(str); 256d697e30cSYuri Pudgorodskiy 257d697e30cSYuri Pudgorodskiy return args; 258d697e30cSYuri Pudgorodskiy } 259d697e30cSYuri Pudgorodskiy 260d697e30cSYuri Pudgorodskiy static void guest_exec_child_watch(GPid pid, gint status, gpointer data) 261d697e30cSYuri Pudgorodskiy { 262d697e30cSYuri Pudgorodskiy GuestExecInfo *gei = (GuestExecInfo *)data; 263d697e30cSYuri Pudgorodskiy 264d697e30cSYuri Pudgorodskiy g_debug("guest_exec_child_watch called, pid: %d, status: %u", 265d697e30cSYuri Pudgorodskiy (int32_t)gpid_to_int64(pid), (uint32_t)status); 266d697e30cSYuri Pudgorodskiy 267d697e30cSYuri Pudgorodskiy gei->status = status; 268a31393e7SAlex Bennée atomic_mb_set(&gei->finished, true); 269d697e30cSYuri Pudgorodskiy 270d697e30cSYuri Pudgorodskiy g_spawn_close_pid(pid); 271d697e30cSYuri Pudgorodskiy } 272d697e30cSYuri Pudgorodskiy 2734005b473SDenis V. Lunev /** Reset ignored signals back to default. */ 2744005b473SDenis V. Lunev static void guest_exec_task_setup(gpointer data) 2754005b473SDenis V. Lunev { 2764005b473SDenis V. Lunev #if !defined(G_OS_WIN32) 2774005b473SDenis V. Lunev struct sigaction sigact; 2784005b473SDenis V. Lunev 2794005b473SDenis V. Lunev memset(&sigact, 0, sizeof(struct sigaction)); 2804005b473SDenis V. Lunev sigact.sa_handler = SIG_DFL; 2814005b473SDenis V. Lunev 2824005b473SDenis V. Lunev if (sigaction(SIGPIPE, &sigact, NULL) != 0) { 2834005b473SDenis V. Lunev slog("sigaction() failed to reset child process's SIGPIPE: %s", 2844005b473SDenis V. Lunev strerror(errno)); 2854005b473SDenis V. Lunev } 2864005b473SDenis V. Lunev #endif 2874005b473SDenis V. Lunev } 2884005b473SDenis V. Lunev 289a1853dcaSYuri Pudgorodskiy static gboolean guest_exec_input_watch(GIOChannel *ch, 290a1853dcaSYuri Pudgorodskiy GIOCondition cond, gpointer p_) 291a1853dcaSYuri Pudgorodskiy { 292a1853dcaSYuri Pudgorodskiy GuestExecIOData *p = (GuestExecIOData *)p_; 293a1853dcaSYuri Pudgorodskiy gsize bytes_written = 0; 294a1853dcaSYuri Pudgorodskiy GIOStatus status; 295a1853dcaSYuri Pudgorodskiy GError *gerr = NULL; 296a1853dcaSYuri Pudgorodskiy 297a1853dcaSYuri Pudgorodskiy /* nothing left to write */ 298a1853dcaSYuri Pudgorodskiy if (p->size == p->length) { 299a1853dcaSYuri Pudgorodskiy goto done; 300a1853dcaSYuri Pudgorodskiy } 301a1853dcaSYuri Pudgorodskiy 302a1853dcaSYuri Pudgorodskiy status = g_io_channel_write_chars(ch, (gchar *)p->data + p->length, 303a1853dcaSYuri Pudgorodskiy p->size - p->length, &bytes_written, &gerr); 304a1853dcaSYuri Pudgorodskiy 305a1853dcaSYuri Pudgorodskiy /* can be not 0 even if not G_IO_STATUS_NORMAL */ 306a1853dcaSYuri Pudgorodskiy if (bytes_written != 0) { 307a1853dcaSYuri Pudgorodskiy p->length += bytes_written; 308a1853dcaSYuri Pudgorodskiy } 309a1853dcaSYuri Pudgorodskiy 310a1853dcaSYuri Pudgorodskiy /* continue write, our callback will be called again */ 311a1853dcaSYuri Pudgorodskiy if (status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_AGAIN) { 312a1853dcaSYuri Pudgorodskiy return true; 313a1853dcaSYuri Pudgorodskiy } 314a1853dcaSYuri Pudgorodskiy 315a1853dcaSYuri Pudgorodskiy if (gerr) { 316a1853dcaSYuri Pudgorodskiy g_warning("qga: i/o error writing to input_data channel: %s", 317a1853dcaSYuri Pudgorodskiy gerr->message); 318a1853dcaSYuri Pudgorodskiy g_error_free(gerr); 319a1853dcaSYuri Pudgorodskiy } 320a1853dcaSYuri Pudgorodskiy 321a1853dcaSYuri Pudgorodskiy done: 322a1853dcaSYuri Pudgorodskiy g_io_channel_shutdown(ch, true, NULL); 323a1853dcaSYuri Pudgorodskiy g_io_channel_unref(ch); 324a31393e7SAlex Bennée atomic_mb_set(&p->closed, true); 325a1853dcaSYuri Pudgorodskiy g_free(p->data); 326a1853dcaSYuri Pudgorodskiy 327a1853dcaSYuri Pudgorodskiy return false; 328a1853dcaSYuri Pudgorodskiy } 329a1853dcaSYuri Pudgorodskiy 330a1853dcaSYuri Pudgorodskiy static gboolean guest_exec_output_watch(GIOChannel *ch, 331a1853dcaSYuri Pudgorodskiy GIOCondition cond, gpointer p_) 332a1853dcaSYuri Pudgorodskiy { 333a1853dcaSYuri Pudgorodskiy GuestExecIOData *p = (GuestExecIOData *)p_; 334a1853dcaSYuri Pudgorodskiy gsize bytes_read; 335a1853dcaSYuri Pudgorodskiy GIOStatus gstatus; 336a1853dcaSYuri Pudgorodskiy 337a1853dcaSYuri Pudgorodskiy if (cond == G_IO_HUP || cond == G_IO_ERR) { 338a1853dcaSYuri Pudgorodskiy goto close; 339a1853dcaSYuri Pudgorodskiy } 340a1853dcaSYuri Pudgorodskiy 341a1853dcaSYuri Pudgorodskiy if (p->size == p->length) { 342a1853dcaSYuri Pudgorodskiy gpointer t = NULL; 343a1853dcaSYuri Pudgorodskiy if (!p->truncated && p->size < GUEST_EXEC_MAX_OUTPUT) { 344a1853dcaSYuri Pudgorodskiy t = g_try_realloc(p->data, p->size + GUEST_EXEC_IO_SIZE); 345a1853dcaSYuri Pudgorodskiy } 346a1853dcaSYuri Pudgorodskiy if (t == NULL) { 347a1853dcaSYuri Pudgorodskiy /* ignore truncated output */ 348a1853dcaSYuri Pudgorodskiy gchar buf[GUEST_EXEC_IO_SIZE]; 349a1853dcaSYuri Pudgorodskiy 350a1853dcaSYuri Pudgorodskiy p->truncated = true; 351a1853dcaSYuri Pudgorodskiy gstatus = g_io_channel_read_chars(ch, buf, sizeof(buf), 352a1853dcaSYuri Pudgorodskiy &bytes_read, NULL); 353a1853dcaSYuri Pudgorodskiy if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) { 354a1853dcaSYuri Pudgorodskiy goto close; 355a1853dcaSYuri Pudgorodskiy } 356a1853dcaSYuri Pudgorodskiy 357a1853dcaSYuri Pudgorodskiy return true; 358a1853dcaSYuri Pudgorodskiy } 359a1853dcaSYuri Pudgorodskiy p->size += GUEST_EXEC_IO_SIZE; 360a1853dcaSYuri Pudgorodskiy p->data = t; 361a1853dcaSYuri Pudgorodskiy } 362a1853dcaSYuri Pudgorodskiy 363a1853dcaSYuri Pudgorodskiy /* Calling read API once. 364a1853dcaSYuri Pudgorodskiy * On next available data our callback will be called again */ 365a1853dcaSYuri Pudgorodskiy gstatus = g_io_channel_read_chars(ch, (gchar *)p->data + p->length, 366a1853dcaSYuri Pudgorodskiy p->size - p->length, &bytes_read, NULL); 367a1853dcaSYuri Pudgorodskiy if (gstatus == G_IO_STATUS_EOF || gstatus == G_IO_STATUS_ERROR) { 368a1853dcaSYuri Pudgorodskiy goto close; 369a1853dcaSYuri Pudgorodskiy } 370a1853dcaSYuri Pudgorodskiy 371a1853dcaSYuri Pudgorodskiy p->length += bytes_read; 372a1853dcaSYuri Pudgorodskiy 373a1853dcaSYuri Pudgorodskiy return true; 374a1853dcaSYuri Pudgorodskiy 375a1853dcaSYuri Pudgorodskiy close: 3763005c2c2SYuriy Pudgorodskiy g_io_channel_shutdown(ch, true, NULL); 377a1853dcaSYuri Pudgorodskiy g_io_channel_unref(ch); 378a31393e7SAlex Bennée atomic_mb_set(&p->closed, true); 379a1853dcaSYuri Pudgorodskiy return false; 380a1853dcaSYuri Pudgorodskiy } 381a1853dcaSYuri Pudgorodskiy 382d697e30cSYuri Pudgorodskiy GuestExec *qmp_guest_exec(const char *path, 383d697e30cSYuri Pudgorodskiy bool has_arg, strList *arg, 384d697e30cSYuri Pudgorodskiy bool has_env, strList *env, 385d697e30cSYuri Pudgorodskiy bool has_input_data, const char *input_data, 386d697e30cSYuri Pudgorodskiy bool has_capture_output, bool capture_output, 387d697e30cSYuri Pudgorodskiy Error **err) 388d697e30cSYuri Pudgorodskiy { 389d697e30cSYuri Pudgorodskiy GPid pid; 390d697e30cSYuri Pudgorodskiy GuestExec *ge = NULL; 391d697e30cSYuri Pudgorodskiy GuestExecInfo *gei; 392d697e30cSYuri Pudgorodskiy char **argv, **envp; 393d697e30cSYuri Pudgorodskiy strList arglist; 394d697e30cSYuri Pudgorodskiy gboolean ret; 395d697e30cSYuri Pudgorodskiy GError *gerr = NULL; 396a1853dcaSYuri Pudgorodskiy gint in_fd, out_fd, err_fd; 397a1853dcaSYuri Pudgorodskiy GIOChannel *in_ch, *out_ch, *err_ch; 398a1853dcaSYuri Pudgorodskiy GSpawnFlags flags; 399a1853dcaSYuri Pudgorodskiy bool has_output = (has_capture_output && capture_output); 400920639caSDaniel P. Berrange uint8_t *input = NULL; 401920639caSDaniel P. Berrange size_t ninput = 0; 402d697e30cSYuri Pudgorodskiy 403d697e30cSYuri Pudgorodskiy arglist.value = (char *)path; 404d697e30cSYuri Pudgorodskiy arglist.next = has_arg ? arg : NULL; 405d697e30cSYuri Pudgorodskiy 406920639caSDaniel P. Berrange if (has_input_data) { 407920639caSDaniel P. Berrange input = qbase64_decode(input_data, -1, &ninput, err); 408920639caSDaniel P. Berrange if (!input) { 409920639caSDaniel P. Berrange return NULL; 410920639caSDaniel P. Berrange } 411920639caSDaniel P. Berrange } 412920639caSDaniel P. Berrange 413d697e30cSYuri Pudgorodskiy argv = guest_exec_get_args(&arglist, true); 41402a4d82eSYuri Pudgorodskiy envp = has_env ? guest_exec_get_args(env, false) : NULL; 415d697e30cSYuri Pudgorodskiy 416a1853dcaSYuri Pudgorodskiy flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD; 4170be40839SYuri Pudgorodskiy #if GLIB_CHECK_VERSION(2, 33, 2) 4180be40839SYuri Pudgorodskiy flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP; 4190be40839SYuri Pudgorodskiy #endif 420a1853dcaSYuri Pudgorodskiy if (!has_output) { 421a1853dcaSYuri Pudgorodskiy flags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; 422a1853dcaSYuri Pudgorodskiy } 423a1853dcaSYuri Pudgorodskiy 424a1853dcaSYuri Pudgorodskiy ret = g_spawn_async_with_pipes(NULL, argv, envp, flags, 425a1853dcaSYuri Pudgorodskiy guest_exec_task_setup, NULL, &pid, has_input_data ? &in_fd : NULL, 426a1853dcaSYuri Pudgorodskiy has_output ? &out_fd : NULL, has_output ? &err_fd : NULL, &gerr); 427d697e30cSYuri Pudgorodskiy if (!ret) { 428d697e30cSYuri Pudgorodskiy error_setg(err, QERR_QGA_COMMAND_FAILED, gerr->message); 429d697e30cSYuri Pudgorodskiy g_error_free(gerr); 430d697e30cSYuri Pudgorodskiy goto done; 431d697e30cSYuri Pudgorodskiy } 432d697e30cSYuri Pudgorodskiy 433d697e30cSYuri Pudgorodskiy ge = g_new0(GuestExec, 1); 434d697e30cSYuri Pudgorodskiy ge->pid = gpid_to_int64(pid); 435d697e30cSYuri Pudgorodskiy 436d697e30cSYuri Pudgorodskiy gei = guest_exec_info_add(pid); 437a1853dcaSYuri Pudgorodskiy gei->has_output = has_output; 438d697e30cSYuri Pudgorodskiy g_child_watch_add(pid, guest_exec_child_watch, gei); 439d697e30cSYuri Pudgorodskiy 440a1853dcaSYuri Pudgorodskiy if (has_input_data) { 441920639caSDaniel P. Berrange gei->in.data = input; 442920639caSDaniel P. Berrange gei->in.size = ninput; 443a1853dcaSYuri Pudgorodskiy #ifdef G_OS_WIN32 444a1853dcaSYuri Pudgorodskiy in_ch = g_io_channel_win32_new_fd(in_fd); 445a1853dcaSYuri Pudgorodskiy #else 446a1853dcaSYuri Pudgorodskiy in_ch = g_io_channel_unix_new(in_fd); 447a1853dcaSYuri Pudgorodskiy #endif 448a1853dcaSYuri Pudgorodskiy g_io_channel_set_encoding(in_ch, NULL, NULL); 449a1853dcaSYuri Pudgorodskiy g_io_channel_set_buffered(in_ch, false); 450a1853dcaSYuri Pudgorodskiy g_io_channel_set_flags(in_ch, G_IO_FLAG_NONBLOCK, NULL); 4513005c2c2SYuriy Pudgorodskiy g_io_channel_set_close_on_unref(in_ch, true); 452a1853dcaSYuri Pudgorodskiy g_io_add_watch(in_ch, G_IO_OUT, guest_exec_input_watch, &gei->in); 453a1853dcaSYuri Pudgorodskiy } 454a1853dcaSYuri Pudgorodskiy 455a1853dcaSYuri Pudgorodskiy if (has_output) { 456a1853dcaSYuri Pudgorodskiy #ifdef G_OS_WIN32 457a1853dcaSYuri Pudgorodskiy out_ch = g_io_channel_win32_new_fd(out_fd); 458a1853dcaSYuri Pudgorodskiy err_ch = g_io_channel_win32_new_fd(err_fd); 459a1853dcaSYuri Pudgorodskiy #else 460a1853dcaSYuri Pudgorodskiy out_ch = g_io_channel_unix_new(out_fd); 461a1853dcaSYuri Pudgorodskiy err_ch = g_io_channel_unix_new(err_fd); 462a1853dcaSYuri Pudgorodskiy #endif 463a1853dcaSYuri Pudgorodskiy g_io_channel_set_encoding(out_ch, NULL, NULL); 464a1853dcaSYuri Pudgorodskiy g_io_channel_set_encoding(err_ch, NULL, NULL); 465a1853dcaSYuri Pudgorodskiy g_io_channel_set_buffered(out_ch, false); 466a1853dcaSYuri Pudgorodskiy g_io_channel_set_buffered(err_ch, false); 4673005c2c2SYuriy Pudgorodskiy g_io_channel_set_close_on_unref(out_ch, true); 4683005c2c2SYuriy Pudgorodskiy g_io_channel_set_close_on_unref(err_ch, true); 469a1853dcaSYuri Pudgorodskiy g_io_add_watch(out_ch, G_IO_IN | G_IO_HUP, 470a1853dcaSYuri Pudgorodskiy guest_exec_output_watch, &gei->out); 471a1853dcaSYuri Pudgorodskiy g_io_add_watch(err_ch, G_IO_IN | G_IO_HUP, 472a1853dcaSYuri Pudgorodskiy guest_exec_output_watch, &gei->err); 473a1853dcaSYuri Pudgorodskiy } 474a1853dcaSYuri Pudgorodskiy 475d697e30cSYuri Pudgorodskiy done: 476d697e30cSYuri Pudgorodskiy g_free(argv); 477d697e30cSYuri Pudgorodskiy g_free(envp); 478d697e30cSYuri Pudgorodskiy 479d697e30cSYuri Pudgorodskiy return ge; 480d697e30cSYuri Pudgorodskiy } 4810b4b4938SEric Blake 4820b4b4938SEric Blake /* Convert GuestFileWhence (either a raw integer or an enum value) into 4830b4b4938SEric Blake * the guest's SEEK_ constants. */ 4840b4b4938SEric Blake int ga_parse_whence(GuestFileWhence *whence, Error **errp) 4850b4b4938SEric Blake { 4860b4b4938SEric Blake /* Exploit the fact that we picked values to match QGA_SEEK_*. */ 4870b4b4938SEric Blake if (whence->type == QTYPE_QSTRING) { 488*01b2ffceSMarc-André Lureau whence->type = QTYPE_QNUM; 4890b4b4938SEric Blake whence->u.value = whence->u.name; 4900b4b4938SEric Blake } 4910b4b4938SEric Blake switch (whence->u.value) { 4920b4b4938SEric Blake case QGA_SEEK_SET: 4930b4b4938SEric Blake return SEEK_SET; 4940b4b4938SEric Blake case QGA_SEEK_CUR: 4950b4b4938SEric Blake return SEEK_CUR; 4960b4b4938SEric Blake case QGA_SEEK_END: 4970b4b4938SEric Blake return SEEK_END; 4980b4b4938SEric Blake } 4990b4b4938SEric Blake error_setg(errp, "invalid whence code %"PRId64, whence->u.value); 5000b4b4938SEric Blake return -1; 5010b4b4938SEric Blake } 5020a3d197aSVinzenz Feenstra 5030a3d197aSVinzenz Feenstra GuestHostName *qmp_guest_get_host_name(Error **err) 5040a3d197aSVinzenz Feenstra { 5050a3d197aSVinzenz Feenstra GuestHostName *result = NULL; 5060a3d197aSVinzenz Feenstra gchar const *hostname = g_get_host_name(); 5070a3d197aSVinzenz Feenstra if (hostname != NULL) { 5080a3d197aSVinzenz Feenstra result = g_new0(GuestHostName, 1); 5090a3d197aSVinzenz Feenstra result->host_name = g_strdup(hostname); 5100a3d197aSVinzenz Feenstra } 5110a3d197aSVinzenz Feenstra return result; 5120a3d197aSVinzenz Feenstra } 51353c58e64SVinzenz Feenstra 51453c58e64SVinzenz Feenstra GuestTimezone *qmp_guest_get_timezone(Error **errp) 51553c58e64SVinzenz Feenstra { 51653c58e64SVinzenz Feenstra #if GLIB_CHECK_VERSION(2, 28, 0) 51753c58e64SVinzenz Feenstra GuestTimezone *info = NULL; 51853c58e64SVinzenz Feenstra GTimeZone *tz = NULL; 51953c58e64SVinzenz Feenstra gint64 now = 0; 52053c58e64SVinzenz Feenstra gint32 intv = 0; 52153c58e64SVinzenz Feenstra gchar const *name = NULL; 52253c58e64SVinzenz Feenstra 52353c58e64SVinzenz Feenstra info = g_new0(GuestTimezone, 1); 52453c58e64SVinzenz Feenstra tz = g_time_zone_new_local(); 52553c58e64SVinzenz Feenstra if (tz == NULL) { 52653c58e64SVinzenz Feenstra error_setg(errp, QERR_QGA_COMMAND_FAILED, 52753c58e64SVinzenz Feenstra "Couldn't retrieve local timezone"); 52853c58e64SVinzenz Feenstra goto error; 52953c58e64SVinzenz Feenstra } 53053c58e64SVinzenz Feenstra 53153c58e64SVinzenz Feenstra now = g_get_real_time() / G_USEC_PER_SEC; 53253c58e64SVinzenz Feenstra intv = g_time_zone_find_interval(tz, G_TIME_TYPE_UNIVERSAL, now); 53353c58e64SVinzenz Feenstra info->offset = g_time_zone_get_offset(tz, intv); 53453c58e64SVinzenz Feenstra name = g_time_zone_get_abbreviation(tz, intv); 53553c58e64SVinzenz Feenstra if (name != NULL) { 53653c58e64SVinzenz Feenstra info->has_zone = true; 53753c58e64SVinzenz Feenstra info->zone = g_strdup(name); 53853c58e64SVinzenz Feenstra } 53953c58e64SVinzenz Feenstra g_time_zone_unref(tz); 54053c58e64SVinzenz Feenstra 54153c58e64SVinzenz Feenstra return info; 54253c58e64SVinzenz Feenstra 54353c58e64SVinzenz Feenstra error: 54453c58e64SVinzenz Feenstra g_free(info); 54553c58e64SVinzenz Feenstra return NULL; 54653c58e64SVinzenz Feenstra #else 54753c58e64SVinzenz Feenstra error_setg(errp, QERR_UNSUPPORTED); 54853c58e64SVinzenz Feenstra return NULL; 54953c58e64SVinzenz Feenstra #endif 55053c58e64SVinzenz Feenstra } 551