#include "module.h"
#include "signal.h"
#include "qerror.h"
-#include "error_int.h"
#include "qapi/qmp-core.h"
#include "qga/channel.h"
#ifdef _WIN32
#else
#define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0"
#endif
-#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
-#define QGA_STATEDIR_DEFAULT "/tmp"
+#define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run"
+#define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid"
#define QGA_SENTINEL_BYTE 0xFF
struct GAState {
}
#ifndef _WIN32
-/* reap _all_ terminated children */
-static void child_handler(int sig)
-{
- int status;
- while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */;
-}
-
static gboolean register_signal_handlers(void)
{
- struct sigaction sigact, sigact_chld;
+ struct sigaction sigact;
int ret;
memset(&sigact, 0, sizeof(struct sigaction));
ret = sigaction(SIGINT, &sigact, NULL);
if (ret == -1) {
g_error("error configuring signal handler: %s", strerror(errno));
- return false;
}
ret = sigaction(SIGTERM, &sigact, NULL);
if (ret == -1) {
g_error("error configuring signal handler: %s", strerror(errno));
- return false;
}
- memset(&sigact_chld, 0, sizeof(struct sigaction));
- sigact_chld.sa_handler = child_handler;
- sigact_chld.sa_flags = SA_NOCLDSTOP;
- ret = sigaction(SIGCHLD, &sigact_chld, NULL);
- if (ret == -1) {
- g_error("error configuring signal handler: %s", strerror(errno));
+ return true;
+}
+
+/* TODO: use this in place of all post-fork() fclose(std*) callers */
+void reopen_fd_to_null(int fd)
+{
+ int nullfd;
+
+ nullfd = open("/dev/null", O_RDWR);
+ if (nullfd < 0) {
+ return;
}
- return true;
+ dup2(nullfd, fd);
+
+ if (nullfd != fd) {
+ close(nullfd);
+ }
}
#endif
" -h, --help display this help and exit\n"
"\n"
- , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
+ , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
QGA_STATEDIR_DEFAULT);
}
pidfd = open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) {
g_critical("Cannot lock pid file, %s", strerror(errno));
+ if (pidfd != -1) {
+ close(pidfd);
+ }
return false;
}
g_critical("Failed to truncate pid file");
goto fail;
}
- sprintf(pidstr, "%d", getpid());
+ snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
g_critical("Failed to write pid file");
goto fail;
goto fail;
}
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
+ reopen_fd_to_null(STDIN_FILENO);
+ reopen_fd_to_null(STDOUT_FILENO);
+ reopen_fd_to_null(STDERR_FILENO);
return;
fail:
- unlink(pidfile);
+ if (pidfile) {
+ unlink(pidfile);
+ }
g_critical("failed to daemonize");
exit(EXIT_FAILURE);
#endif
g_warning("error sending response: %s", strerror(ret));
}
qobject_decref(rsp);
- } else {
- g_warning("error getting response");
}
}
} else {
g_warning("failed to parse event: %s", error_get_pretty(err));
}
- qdict_put_obj(qdict, "error", error_get_qobject(err));
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
error_free(err);
} else {
qdict = qobject_to_qdict(obj);
qdict = qdict_new();
g_warning("unrecognized payload format");
error_set(&err, QERR_UNSUPPORTED);
- qdict_put_obj(qdict, "error", error_get_qobject(err));
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
error_free(err);
}
ret = send_response(s, QOBJECT(qdict));
log_level = G_LOG_LEVEL_MASK;
break;
case 'V':
- printf("QEMU Guest Agent %s\n", QGA_VERSION);
+ printf("QEMU Guest Agent %s\n", QEMU_VERSION);
return 0;
case 'd':
daemonize = 1;
break;
case 'b': {
char **list_head, **list;
- if (*optarg == '?') {
+ if (is_help_option(optarg)) {
list_head = list = qmp_get_command_list();
while (*list != NULL) {
printf("%s\n", *list);
become_daemon(pid_filepath);
}
if (log_filepath) {
- s->log_file = fopen(log_filepath, "a");
- if (!s->log_file) {
+ FILE *log_file = fopen(log_filepath, "a");
+ if (!log_file) {
g_critical("unable to open specified log file: %s",
strerror(errno));
goto out_bad;
}
+ s->log_file = log_file;
}
}