root / qemu-ga.c @ fb5590f7
History | View | Annotate | Download (18.6 kB)
1 | 48ff7a62 | Michael Roth | /*
|
---|---|---|---|
2 | 48ff7a62 | Michael Roth | * QEMU Guest Agent
|
3 | 48ff7a62 | Michael Roth | *
|
4 | 48ff7a62 | Michael Roth | * Copyright IBM Corp. 2011
|
5 | 48ff7a62 | Michael Roth | *
|
6 | 48ff7a62 | Michael Roth | * Authors:
|
7 | 48ff7a62 | Michael Roth | * Adam Litke <aglitke@linux.vnet.ibm.com>
|
8 | 48ff7a62 | Michael Roth | * Michael Roth <mdroth@linux.vnet.ibm.com>
|
9 | 48ff7a62 | Michael Roth | *
|
10 | 48ff7a62 | Michael Roth | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
11 | 48ff7a62 | Michael Roth | * See the COPYING file in the top-level directory.
|
12 | 48ff7a62 | Michael Roth | */
|
13 | 48ff7a62 | Michael Roth | #include <stdlib.h> |
14 | 48ff7a62 | Michael Roth | #include <stdio.h> |
15 | 48ff7a62 | Michael Roth | #include <stdbool.h> |
16 | 48ff7a62 | Michael Roth | #include <glib.h> |
17 | 48ff7a62 | Michael Roth | #include <getopt.h> |
18 | 48ff7a62 | Michael Roth | #include <termios.h> |
19 | 48ff7a62 | Michael Roth | #include <syslog.h> |
20 | 48ff7a62 | Michael Roth | #include "qemu_socket.h" |
21 | 48ff7a62 | Michael Roth | #include "json-streamer.h" |
22 | 48ff7a62 | Michael Roth | #include "json-parser.h" |
23 | 48ff7a62 | Michael Roth | #include "qint.h" |
24 | 48ff7a62 | Michael Roth | #include "qjson.h" |
25 | 48ff7a62 | Michael Roth | #include "qga/guest-agent-core.h" |
26 | 48ff7a62 | Michael Roth | #include "module.h" |
27 | 48ff7a62 | Michael Roth | #include "signal.h" |
28 | 48ff7a62 | Michael Roth | #include "qerror.h" |
29 | 48ff7a62 | Michael Roth | #include "error_int.h" |
30 | abd6cf6d | Michael Roth | #include "qapi/qmp-core.h" |
31 | 48ff7a62 | Michael Roth | |
32 | 48ff7a62 | Michael Roth | #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" |
33 | 48ff7a62 | Michael Roth | #define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid" |
34 | 48ff7a62 | Michael Roth | #define QGA_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */ |
35 | 48ff7a62 | Michael Roth | #define QGA_TIMEOUT_DEFAULT 30*1000 /* ms */ |
36 | 48ff7a62 | Michael Roth | |
37 | 48ff7a62 | Michael Roth | struct GAState {
|
38 | 48ff7a62 | Michael Roth | JSONMessageParser parser; |
39 | 48ff7a62 | Michael Roth | GMainLoop *main_loop; |
40 | 48ff7a62 | Michael Roth | GIOChannel *conn_channel; |
41 | 48ff7a62 | Michael Roth | GIOChannel *listen_channel; |
42 | 48ff7a62 | Michael Roth | const char *path; |
43 | 48ff7a62 | Michael Roth | const char *method; |
44 | 48ff7a62 | Michael Roth | bool virtio; /* fastpath to check for virtio to deal with poll() quirks */ |
45 | 48ff7a62 | Michael Roth | GACommandState *command_state; |
46 | 48ff7a62 | Michael Roth | GLogLevelFlags log_level; |
47 | 48ff7a62 | Michael Roth | FILE *log_file; |
48 | 48ff7a62 | Michael Roth | bool logging_enabled;
|
49 | 48ff7a62 | Michael Roth | }; |
50 | 48ff7a62 | Michael Roth | |
51 | 48ff7a62 | Michael Roth | static struct GAState *ga_state; |
52 | 48ff7a62 | Michael Roth | |
53 | 48ff7a62 | Michael Roth | static void quit_handler(int sig) |
54 | 48ff7a62 | Michael Roth | { |
55 | 2542bfd5 | Stefan Weil | g_debug("received signal num %d, quitting", sig);
|
56 | 48ff7a62 | Michael Roth | |
57 | 48ff7a62 | Michael Roth | if (g_main_loop_is_running(ga_state->main_loop)) {
|
58 | 48ff7a62 | Michael Roth | g_main_loop_quit(ga_state->main_loop); |
59 | 48ff7a62 | Michael Roth | } |
60 | 48ff7a62 | Michael Roth | } |
61 | 48ff7a62 | Michael Roth | |
62 | 48ff7a62 | Michael Roth | static void register_signal_handlers(void) |
63 | 48ff7a62 | Michael Roth | { |
64 | 48ff7a62 | Michael Roth | struct sigaction sigact;
|
65 | 48ff7a62 | Michael Roth | int ret;
|
66 | 48ff7a62 | Michael Roth | |
67 | 48ff7a62 | Michael Roth | memset(&sigact, 0, sizeof(struct sigaction)); |
68 | 48ff7a62 | Michael Roth | sigact.sa_handler = quit_handler; |
69 | 48ff7a62 | Michael Roth | |
70 | 48ff7a62 | Michael Roth | ret = sigaction(SIGINT, &sigact, NULL);
|
71 | 48ff7a62 | Michael Roth | if (ret == -1) { |
72 | 48ff7a62 | Michael Roth | g_error("error configuring signal handler: %s", strerror(errno));
|
73 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
74 | 48ff7a62 | Michael Roth | } |
75 | 48ff7a62 | Michael Roth | ret = sigaction(SIGTERM, &sigact, NULL);
|
76 | 48ff7a62 | Michael Roth | if (ret == -1) { |
77 | 48ff7a62 | Michael Roth | g_error("error configuring signal handler: %s", strerror(errno));
|
78 | 48ff7a62 | Michael Roth | } |
79 | 48ff7a62 | Michael Roth | } |
80 | 48ff7a62 | Michael Roth | |
81 | 48ff7a62 | Michael Roth | static void usage(const char *cmd) |
82 | 48ff7a62 | Michael Roth | { |
83 | 48ff7a62 | Michael Roth | printf( |
84 | 48ff7a62 | Michael Roth | "Usage: %s -c <channel_opts>\n"
|
85 | 48ff7a62 | Michael Roth | "QEMU Guest Agent %s\n"
|
86 | 48ff7a62 | Michael Roth | "\n"
|
87 | 48ff7a62 | Michael Roth | " -m, --method transport method: one of unix-listen, virtio-serial, or\n"
|
88 | 48ff7a62 | Michael Roth | " isa-serial (virtio-serial is the default)\n"
|
89 | 48ff7a62 | Michael Roth | " -p, --path device/socket path (%s is the default for virtio-serial)\n"
|
90 | 48ff7a62 | Michael Roth | " -l, --logfile set logfile path, logs to stderr by default\n"
|
91 | 48ff7a62 | Michael Roth | " -f, --pidfile specify pidfile (default is %s)\n"
|
92 | 48ff7a62 | Michael Roth | " -v, --verbose log extra debugging information\n"
|
93 | 48ff7a62 | Michael Roth | " -V, --version print version information and exit\n"
|
94 | 48ff7a62 | Michael Roth | " -d, --daemonize become a daemon\n"
|
95 | dabdf394 | Stefan Weil | " -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\""
|
96 | abd6cf6d | Michael Roth | " to list available RPCs)\n"
|
97 | 48ff7a62 | Michael Roth | " -h, --help display this help and exit\n"
|
98 | 48ff7a62 | Michael Roth | "\n"
|
99 | 48ff7a62 | Michael Roth | "Report bugs to <mdroth@linux.vnet.ibm.com>\n"
|
100 | 48ff7a62 | Michael Roth | , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT); |
101 | 48ff7a62 | Michael Roth | } |
102 | 48ff7a62 | Michael Roth | |
103 | 48ff7a62 | Michael Roth | static void conn_channel_close(GAState *s); |
104 | 48ff7a62 | Michael Roth | |
105 | 48ff7a62 | Michael Roth | static const char *ga_log_level_str(GLogLevelFlags level) |
106 | 48ff7a62 | Michael Roth | { |
107 | 48ff7a62 | Michael Roth | switch (level & G_LOG_LEVEL_MASK) {
|
108 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_ERROR:
|
109 | 48ff7a62 | Michael Roth | return "error"; |
110 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_CRITICAL:
|
111 | 48ff7a62 | Michael Roth | return "critical"; |
112 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_WARNING:
|
113 | 48ff7a62 | Michael Roth | return "warning"; |
114 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_MESSAGE:
|
115 | 48ff7a62 | Michael Roth | return "message"; |
116 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_INFO:
|
117 | 48ff7a62 | Michael Roth | return "info"; |
118 | 48ff7a62 | Michael Roth | case G_LOG_LEVEL_DEBUG:
|
119 | 48ff7a62 | Michael Roth | return "debug"; |
120 | 48ff7a62 | Michael Roth | default:
|
121 | 48ff7a62 | Michael Roth | return "user"; |
122 | 48ff7a62 | Michael Roth | } |
123 | 48ff7a62 | Michael Roth | } |
124 | 48ff7a62 | Michael Roth | |
125 | 48ff7a62 | Michael Roth | bool ga_logging_enabled(GAState *s)
|
126 | 48ff7a62 | Michael Roth | { |
127 | 48ff7a62 | Michael Roth | return s->logging_enabled;
|
128 | 48ff7a62 | Michael Roth | } |
129 | 48ff7a62 | Michael Roth | |
130 | 48ff7a62 | Michael Roth | void ga_disable_logging(GAState *s)
|
131 | 48ff7a62 | Michael Roth | { |
132 | 48ff7a62 | Michael Roth | s->logging_enabled = false;
|
133 | 48ff7a62 | Michael Roth | } |
134 | 48ff7a62 | Michael Roth | |
135 | 48ff7a62 | Michael Roth | void ga_enable_logging(GAState *s)
|
136 | 48ff7a62 | Michael Roth | { |
137 | 48ff7a62 | Michael Roth | s->logging_enabled = true;
|
138 | 48ff7a62 | Michael Roth | } |
139 | 48ff7a62 | Michael Roth | |
140 | 48ff7a62 | Michael Roth | static void ga_log(const gchar *domain, GLogLevelFlags level, |
141 | 48ff7a62 | Michael Roth | const gchar *msg, gpointer opaque)
|
142 | 48ff7a62 | Michael Roth | { |
143 | 48ff7a62 | Michael Roth | GAState *s = opaque; |
144 | 48ff7a62 | Michael Roth | GTimeVal time; |
145 | 48ff7a62 | Michael Roth | const char *level_str = ga_log_level_str(level); |
146 | 48ff7a62 | Michael Roth | |
147 | 48ff7a62 | Michael Roth | if (!ga_logging_enabled(s)) {
|
148 | 48ff7a62 | Michael Roth | return;
|
149 | 48ff7a62 | Michael Roth | } |
150 | 48ff7a62 | Michael Roth | |
151 | 48ff7a62 | Michael Roth | level &= G_LOG_LEVEL_MASK; |
152 | 8f477478 | Michael Roth | if (domain && strcmp(domain, "syslog") == 0) { |
153 | 48ff7a62 | Michael Roth | syslog(LOG_INFO, "%s: %s", level_str, msg);
|
154 | 48ff7a62 | Michael Roth | } else if (level & s->log_level) { |
155 | 48ff7a62 | Michael Roth | g_get_current_time(&time); |
156 | 48ff7a62 | Michael Roth | fprintf(s->log_file, |
157 | 48ff7a62 | Michael Roth | "%lu.%lu: %s: %s\n", time.tv_sec, time.tv_usec, level_str, msg);
|
158 | 48ff7a62 | Michael Roth | fflush(s->log_file); |
159 | 48ff7a62 | Michael Roth | } |
160 | 48ff7a62 | Michael Roth | } |
161 | 48ff7a62 | Michael Roth | |
162 | 48ff7a62 | Michael Roth | static void become_daemon(const char *pidfile) |
163 | 48ff7a62 | Michael Roth | { |
164 | 48ff7a62 | Michael Roth | pid_t pid, sid; |
165 | 48ff7a62 | Michael Roth | int pidfd;
|
166 | 48ff7a62 | Michael Roth | char *pidstr = NULL; |
167 | 48ff7a62 | Michael Roth | |
168 | 48ff7a62 | Michael Roth | pid = fork(); |
169 | 48ff7a62 | Michael Roth | if (pid < 0) { |
170 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
171 | 48ff7a62 | Michael Roth | } |
172 | 48ff7a62 | Michael Roth | if (pid > 0) { |
173 | 48ff7a62 | Michael Roth | exit(EXIT_SUCCESS); |
174 | 48ff7a62 | Michael Roth | } |
175 | 48ff7a62 | Michael Roth | |
176 | 48ff7a62 | Michael Roth | pidfd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, S_IRUSR|S_IWUSR); |
177 | 48ff7a62 | Michael Roth | if (pidfd == -1) { |
178 | 48ff7a62 | Michael Roth | g_critical("Cannot create pid file, %s", strerror(errno));
|
179 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
180 | 48ff7a62 | Michael Roth | } |
181 | 48ff7a62 | Michael Roth | |
182 | 48ff7a62 | Michael Roth | if (asprintf(&pidstr, "%d", getpid()) == -1) { |
183 | 48ff7a62 | Michael Roth | g_critical("Cannot allocate memory");
|
184 | 48ff7a62 | Michael Roth | goto fail;
|
185 | 48ff7a62 | Michael Roth | } |
186 | 48ff7a62 | Michael Roth | if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
|
187 | 48ff7a62 | Michael Roth | free(pidstr); |
188 | 48ff7a62 | Michael Roth | g_critical("Failed to write pid file");
|
189 | 48ff7a62 | Michael Roth | goto fail;
|
190 | 48ff7a62 | Michael Roth | } |
191 | 48ff7a62 | Michael Roth | |
192 | 48ff7a62 | Michael Roth | umask(0);
|
193 | 48ff7a62 | Michael Roth | sid = setsid(); |
194 | 48ff7a62 | Michael Roth | if (sid < 0) { |
195 | 48ff7a62 | Michael Roth | goto fail;
|
196 | 48ff7a62 | Michael Roth | } |
197 | 48ff7a62 | Michael Roth | if ((chdir("/")) < 0) { |
198 | 48ff7a62 | Michael Roth | goto fail;
|
199 | 48ff7a62 | Michael Roth | } |
200 | 48ff7a62 | Michael Roth | |
201 | 48ff7a62 | Michael Roth | close(STDIN_FILENO); |
202 | 48ff7a62 | Michael Roth | close(STDOUT_FILENO); |
203 | 48ff7a62 | Michael Roth | close(STDERR_FILENO); |
204 | 48ff7a62 | Michael Roth | free(pidstr); |
205 | 48ff7a62 | Michael Roth | return;
|
206 | 48ff7a62 | Michael Roth | |
207 | 48ff7a62 | Michael Roth | fail:
|
208 | 48ff7a62 | Michael Roth | unlink(pidfile); |
209 | 48ff7a62 | Michael Roth | g_critical("failed to daemonize");
|
210 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
211 | 48ff7a62 | Michael Roth | } |
212 | 48ff7a62 | Michael Roth | |
213 | 48ff7a62 | Michael Roth | static int conn_channel_send_buf(GIOChannel *channel, const char *buf, |
214 | 48ff7a62 | Michael Roth | gsize count) |
215 | 48ff7a62 | Michael Roth | { |
216 | 48ff7a62 | Michael Roth | GError *err = NULL;
|
217 | 48ff7a62 | Michael Roth | gsize written = 0;
|
218 | 48ff7a62 | Michael Roth | GIOStatus status; |
219 | 48ff7a62 | Michael Roth | |
220 | 48ff7a62 | Michael Roth | while (count) {
|
221 | 48ff7a62 | Michael Roth | status = g_io_channel_write_chars(channel, buf, count, &written, &err); |
222 | 48ff7a62 | Michael Roth | g_debug("sending data, count: %d", (int)count); |
223 | 48ff7a62 | Michael Roth | if (err != NULL) { |
224 | 48ff7a62 | Michael Roth | g_warning("error sending newline: %s", err->message);
|
225 | 48ff7a62 | Michael Roth | return err->code;
|
226 | 48ff7a62 | Michael Roth | } |
227 | 48ff7a62 | Michael Roth | if (status == G_IO_STATUS_ERROR || status == G_IO_STATUS_EOF) {
|
228 | 48ff7a62 | Michael Roth | return -EPIPE;
|
229 | 48ff7a62 | Michael Roth | } |
230 | 48ff7a62 | Michael Roth | |
231 | 48ff7a62 | Michael Roth | if (status == G_IO_STATUS_NORMAL) {
|
232 | 48ff7a62 | Michael Roth | count -= written; |
233 | 48ff7a62 | Michael Roth | } |
234 | 48ff7a62 | Michael Roth | } |
235 | 48ff7a62 | Michael Roth | |
236 | 48ff7a62 | Michael Roth | return 0; |
237 | 48ff7a62 | Michael Roth | } |
238 | 48ff7a62 | Michael Roth | |
239 | 48ff7a62 | Michael Roth | static int conn_channel_send_payload(GIOChannel *channel, QObject *payload) |
240 | 48ff7a62 | Michael Roth | { |
241 | 48ff7a62 | Michael Roth | int ret = 0; |
242 | 48ff7a62 | Michael Roth | const char *buf; |
243 | 48ff7a62 | Michael Roth | QString *payload_qstr; |
244 | 48ff7a62 | Michael Roth | GError *err = NULL;
|
245 | 48ff7a62 | Michael Roth | |
246 | 48ff7a62 | Michael Roth | g_assert(payload && channel); |
247 | 48ff7a62 | Michael Roth | |
248 | 48ff7a62 | Michael Roth | payload_qstr = qobject_to_json(payload); |
249 | 48ff7a62 | Michael Roth | if (!payload_qstr) {
|
250 | 48ff7a62 | Michael Roth | return -EINVAL;
|
251 | 48ff7a62 | Michael Roth | } |
252 | 48ff7a62 | Michael Roth | |
253 | 48ff7a62 | Michael Roth | qstring_append_chr(payload_qstr, '\n');
|
254 | 48ff7a62 | Michael Roth | buf = qstring_get_str(payload_qstr); |
255 | 48ff7a62 | Michael Roth | ret = conn_channel_send_buf(channel, buf, strlen(buf)); |
256 | 48ff7a62 | Michael Roth | if (ret) {
|
257 | 48ff7a62 | Michael Roth | goto out_free;
|
258 | 48ff7a62 | Michael Roth | } |
259 | 48ff7a62 | Michael Roth | |
260 | 48ff7a62 | Michael Roth | g_io_channel_flush(channel, &err); |
261 | 48ff7a62 | Michael Roth | if (err != NULL) { |
262 | 48ff7a62 | Michael Roth | g_warning("error flushing payload: %s", err->message);
|
263 | 48ff7a62 | Michael Roth | ret = err->code; |
264 | 48ff7a62 | Michael Roth | goto out_free;
|
265 | 48ff7a62 | Michael Roth | } |
266 | 48ff7a62 | Michael Roth | |
267 | 48ff7a62 | Michael Roth | out_free:
|
268 | 48ff7a62 | Michael Roth | QDECREF(payload_qstr); |
269 | 48ff7a62 | Michael Roth | if (err) {
|
270 | 48ff7a62 | Michael Roth | g_error_free(err); |
271 | 48ff7a62 | Michael Roth | } |
272 | 48ff7a62 | Michael Roth | return ret;
|
273 | 48ff7a62 | Michael Roth | } |
274 | 48ff7a62 | Michael Roth | |
275 | 48ff7a62 | Michael Roth | static void process_command(GAState *s, QDict *req) |
276 | 48ff7a62 | Michael Roth | { |
277 | 48ff7a62 | Michael Roth | QObject *rsp = NULL;
|
278 | 48ff7a62 | Michael Roth | int ret;
|
279 | 48ff7a62 | Michael Roth | |
280 | 48ff7a62 | Michael Roth | g_assert(req); |
281 | 48ff7a62 | Michael Roth | g_debug("processing command");
|
282 | 48ff7a62 | Michael Roth | rsp = qmp_dispatch(QOBJECT(req)); |
283 | 48ff7a62 | Michael Roth | if (rsp) {
|
284 | 48ff7a62 | Michael Roth | ret = conn_channel_send_payload(s->conn_channel, rsp); |
285 | 48ff7a62 | Michael Roth | if (ret) {
|
286 | 48ff7a62 | Michael Roth | g_warning("error sending payload: %s", strerror(ret));
|
287 | 48ff7a62 | Michael Roth | } |
288 | 48ff7a62 | Michael Roth | qobject_decref(rsp); |
289 | 48ff7a62 | Michael Roth | } else {
|
290 | 48ff7a62 | Michael Roth | g_warning("error getting response");
|
291 | 48ff7a62 | Michael Roth | } |
292 | 48ff7a62 | Michael Roth | } |
293 | 48ff7a62 | Michael Roth | |
294 | 48ff7a62 | Michael Roth | /* handle requests/control events coming in over the channel */
|
295 | 48ff7a62 | Michael Roth | static void process_event(JSONMessageParser *parser, QList *tokens) |
296 | 48ff7a62 | Michael Roth | { |
297 | 48ff7a62 | Michael Roth | GAState *s = container_of(parser, GAState, parser); |
298 | 48ff7a62 | Michael Roth | QObject *obj; |
299 | 48ff7a62 | Michael Roth | QDict *qdict; |
300 | 48ff7a62 | Michael Roth | Error *err = NULL;
|
301 | 48ff7a62 | Michael Roth | int ret;
|
302 | 48ff7a62 | Michael Roth | |
303 | 48ff7a62 | Michael Roth | g_assert(s && parser); |
304 | 48ff7a62 | Michael Roth | |
305 | 48ff7a62 | Michael Roth | g_debug("process_event: called");
|
306 | 48ff7a62 | Michael Roth | obj = json_parser_parse_err(tokens, NULL, &err);
|
307 | 48ff7a62 | Michael Roth | if (err || !obj || qobject_type(obj) != QTYPE_QDICT) {
|
308 | 48ff7a62 | Michael Roth | qobject_decref(obj); |
309 | 48ff7a62 | Michael Roth | qdict = qdict_new(); |
310 | 48ff7a62 | Michael Roth | if (!err) {
|
311 | 48ff7a62 | Michael Roth | g_warning("failed to parse event: unknown error");
|
312 | 48ff7a62 | Michael Roth | error_set(&err, QERR_JSON_PARSING); |
313 | 48ff7a62 | Michael Roth | } else {
|
314 | 48ff7a62 | Michael Roth | g_warning("failed to parse event: %s", error_get_pretty(err));
|
315 | 48ff7a62 | Michael Roth | } |
316 | 48ff7a62 | Michael Roth | qdict_put_obj(qdict, "error", error_get_qobject(err));
|
317 | 48ff7a62 | Michael Roth | error_free(err); |
318 | 48ff7a62 | Michael Roth | } else {
|
319 | 48ff7a62 | Michael Roth | qdict = qobject_to_qdict(obj); |
320 | 48ff7a62 | Michael Roth | } |
321 | 48ff7a62 | Michael Roth | |
322 | 48ff7a62 | Michael Roth | g_assert(qdict); |
323 | 48ff7a62 | Michael Roth | |
324 | 48ff7a62 | Michael Roth | /* handle host->guest commands */
|
325 | 48ff7a62 | Michael Roth | if (qdict_haskey(qdict, "execute")) { |
326 | 48ff7a62 | Michael Roth | process_command(s, qdict); |
327 | 48ff7a62 | Michael Roth | } else {
|
328 | 48ff7a62 | Michael Roth | if (!qdict_haskey(qdict, "error")) { |
329 | 48ff7a62 | Michael Roth | QDECREF(qdict); |
330 | 48ff7a62 | Michael Roth | qdict = qdict_new(); |
331 | 48ff7a62 | Michael Roth | g_warning("unrecognized payload format");
|
332 | 48ff7a62 | Michael Roth | error_set(&err, QERR_UNSUPPORTED); |
333 | 48ff7a62 | Michael Roth | qdict_put_obj(qdict, "error", error_get_qobject(err));
|
334 | 48ff7a62 | Michael Roth | error_free(err); |
335 | 48ff7a62 | Michael Roth | } |
336 | 48ff7a62 | Michael Roth | ret = conn_channel_send_payload(s->conn_channel, QOBJECT(qdict)); |
337 | 48ff7a62 | Michael Roth | if (ret) {
|
338 | 48ff7a62 | Michael Roth | g_warning("error sending payload: %s", strerror(ret));
|
339 | 48ff7a62 | Michael Roth | } |
340 | 48ff7a62 | Michael Roth | } |
341 | 48ff7a62 | Michael Roth | |
342 | 48ff7a62 | Michael Roth | QDECREF(qdict); |
343 | 48ff7a62 | Michael Roth | } |
344 | 48ff7a62 | Michael Roth | |
345 | 48ff7a62 | Michael Roth | static gboolean conn_channel_read(GIOChannel *channel, GIOCondition condition,
|
346 | 48ff7a62 | Michael Roth | gpointer data) |
347 | 48ff7a62 | Michael Roth | { |
348 | 48ff7a62 | Michael Roth | GAState *s = data; |
349 | 48ff7a62 | Michael Roth | gchar buf[1024];
|
350 | 48ff7a62 | Michael Roth | gsize count; |
351 | 48ff7a62 | Michael Roth | GError *err = NULL;
|
352 | 48ff7a62 | Michael Roth | memset(buf, 0, 1024); |
353 | 48ff7a62 | Michael Roth | GIOStatus status = g_io_channel_read_chars(channel, buf, 1024,
|
354 | 48ff7a62 | Michael Roth | &count, &err); |
355 | 48ff7a62 | Michael Roth | if (err != NULL) { |
356 | 48ff7a62 | Michael Roth | g_warning("error reading channel: %s", err->message);
|
357 | 48ff7a62 | Michael Roth | conn_channel_close(s); |
358 | 48ff7a62 | Michael Roth | g_error_free(err); |
359 | 48ff7a62 | Michael Roth | return false; |
360 | 48ff7a62 | Michael Roth | } |
361 | 48ff7a62 | Michael Roth | switch (status) {
|
362 | 48ff7a62 | Michael Roth | case G_IO_STATUS_ERROR:
|
363 | 48ff7a62 | Michael Roth | g_warning("problem");
|
364 | 48ff7a62 | Michael Roth | return false; |
365 | 48ff7a62 | Michael Roth | case G_IO_STATUS_NORMAL:
|
366 | 48ff7a62 | Michael Roth | g_debug("read data, count: %d, data: %s", (int)count, buf); |
367 | 48ff7a62 | Michael Roth | json_message_parser_feed(&s->parser, (char *)buf, (int)count); |
368 | 48ff7a62 | Michael Roth | case G_IO_STATUS_AGAIN:
|
369 | 48ff7a62 | Michael Roth | /* virtio causes us to spin here when no process is attached to
|
370 | 48ff7a62 | Michael Roth | * host-side chardev. sleep a bit to mitigate this
|
371 | 48ff7a62 | Michael Roth | */
|
372 | 48ff7a62 | Michael Roth | if (s->virtio) {
|
373 | 48ff7a62 | Michael Roth | usleep(100*1000); |
374 | 48ff7a62 | Michael Roth | } |
375 | 48ff7a62 | Michael Roth | return true; |
376 | 48ff7a62 | Michael Roth | case G_IO_STATUS_EOF:
|
377 | 48ff7a62 | Michael Roth | g_debug("received EOF");
|
378 | 48ff7a62 | Michael Roth | conn_channel_close(s); |
379 | 48ff7a62 | Michael Roth | if (s->virtio) {
|
380 | 48ff7a62 | Michael Roth | return true; |
381 | 48ff7a62 | Michael Roth | } |
382 | 48ff7a62 | Michael Roth | return false; |
383 | 48ff7a62 | Michael Roth | default:
|
384 | 48ff7a62 | Michael Roth | g_warning("unknown channel read status, closing");
|
385 | 48ff7a62 | Michael Roth | conn_channel_close(s); |
386 | 48ff7a62 | Michael Roth | return false; |
387 | 48ff7a62 | Michael Roth | } |
388 | 48ff7a62 | Michael Roth | return true; |
389 | 48ff7a62 | Michael Roth | } |
390 | 48ff7a62 | Michael Roth | |
391 | 48ff7a62 | Michael Roth | static int conn_channel_add(GAState *s, int fd) |
392 | 48ff7a62 | Michael Roth | { |
393 | 48ff7a62 | Michael Roth | GIOChannel *conn_channel; |
394 | 48ff7a62 | Michael Roth | GError *err = NULL;
|
395 | 48ff7a62 | Michael Roth | |
396 | 48ff7a62 | Michael Roth | g_assert(s && !s->conn_channel); |
397 | 48ff7a62 | Michael Roth | conn_channel = g_io_channel_unix_new(fd); |
398 | 48ff7a62 | Michael Roth | g_assert(conn_channel); |
399 | 48ff7a62 | Michael Roth | g_io_channel_set_encoding(conn_channel, NULL, &err);
|
400 | 48ff7a62 | Michael Roth | if (err != NULL) { |
401 | 48ff7a62 | Michael Roth | g_warning("error setting channel encoding to binary");
|
402 | 48ff7a62 | Michael Roth | g_error_free(err); |
403 | 48ff7a62 | Michael Roth | return -1; |
404 | 48ff7a62 | Michael Roth | } |
405 | 48ff7a62 | Michael Roth | g_io_add_watch(conn_channel, G_IO_IN | G_IO_HUP, |
406 | 48ff7a62 | Michael Roth | conn_channel_read, s); |
407 | 48ff7a62 | Michael Roth | s->conn_channel = conn_channel; |
408 | 48ff7a62 | Michael Roth | return 0; |
409 | 48ff7a62 | Michael Roth | } |
410 | 48ff7a62 | Michael Roth | |
411 | 48ff7a62 | Michael Roth | static gboolean listen_channel_accept(GIOChannel *channel,
|
412 | 48ff7a62 | Michael Roth | GIOCondition condition, gpointer data) |
413 | 48ff7a62 | Michael Roth | { |
414 | 48ff7a62 | Michael Roth | GAState *s = data; |
415 | 48ff7a62 | Michael Roth | g_assert(channel != NULL);
|
416 | 1fc7bd4a | Anthony Liguori | int ret, conn_fd;
|
417 | 48ff7a62 | Michael Roth | bool accepted = false; |
418 | 1fc7bd4a | Anthony Liguori | struct sockaddr_un addr;
|
419 | 1fc7bd4a | Anthony Liguori | socklen_t addrlen = sizeof(addr);
|
420 | 48ff7a62 | Michael Roth | |
421 | 1fc7bd4a | Anthony Liguori | conn_fd = qemu_accept(g_io_channel_unix_get_fd(s->listen_channel), |
422 | 1fc7bd4a | Anthony Liguori | (struct sockaddr *)&addr, &addrlen);
|
423 | 1fc7bd4a | Anthony Liguori | if (conn_fd == -1) { |
424 | 1fc7bd4a | Anthony Liguori | g_warning("error converting fd to gsocket: %s", strerror(errno));
|
425 | 48ff7a62 | Michael Roth | goto out;
|
426 | 48ff7a62 | Michael Roth | } |
427 | 1fc7bd4a | Anthony Liguori | fcntl(conn_fd, F_SETFL, O_NONBLOCK); |
428 | 1fc7bd4a | Anthony Liguori | ret = conn_channel_add(s, conn_fd); |
429 | 48ff7a62 | Michael Roth | if (ret) {
|
430 | 48ff7a62 | Michael Roth | g_warning("error setting up connection");
|
431 | 48ff7a62 | Michael Roth | goto out;
|
432 | 48ff7a62 | Michael Roth | } |
433 | 48ff7a62 | Michael Roth | accepted = true;
|
434 | 48ff7a62 | Michael Roth | |
435 | 48ff7a62 | Michael Roth | out:
|
436 | 48ff7a62 | Michael Roth | /* only accept 1 connection at a time */
|
437 | 48ff7a62 | Michael Roth | return !accepted;
|
438 | 48ff7a62 | Michael Roth | } |
439 | 48ff7a62 | Michael Roth | |
440 | 48ff7a62 | Michael Roth | /* start polling for readable events on listen fd, new==true
|
441 | 48ff7a62 | Michael Roth | * indicates we should use the existing s->listen_channel
|
442 | 48ff7a62 | Michael Roth | */
|
443 | 48ff7a62 | Michael Roth | static int listen_channel_add(GAState *s, int listen_fd, bool new) |
444 | 48ff7a62 | Michael Roth | { |
445 | 48ff7a62 | Michael Roth | if (new) {
|
446 | 48ff7a62 | Michael Roth | s->listen_channel = g_io_channel_unix_new(listen_fd); |
447 | 48ff7a62 | Michael Roth | } |
448 | 48ff7a62 | Michael Roth | g_io_add_watch(s->listen_channel, G_IO_IN, |
449 | 48ff7a62 | Michael Roth | listen_channel_accept, s); |
450 | 48ff7a62 | Michael Roth | return 0; |
451 | 48ff7a62 | Michael Roth | } |
452 | 48ff7a62 | Michael Roth | |
453 | 48ff7a62 | Michael Roth | /* cleanup state for closed connection/session, start accepting new
|
454 | 48ff7a62 | Michael Roth | * connections if we're in listening mode
|
455 | 48ff7a62 | Michael Roth | */
|
456 | 48ff7a62 | Michael Roth | static void conn_channel_close(GAState *s) |
457 | 48ff7a62 | Michael Roth | { |
458 | 48ff7a62 | Michael Roth | if (strcmp(s->method, "unix-listen") == 0) { |
459 | 48ff7a62 | Michael Roth | g_io_channel_shutdown(s->conn_channel, true, NULL); |
460 | 48ff7a62 | Michael Roth | listen_channel_add(s, 0, false); |
461 | 48ff7a62 | Michael Roth | } else if (strcmp(s->method, "virtio-serial") == 0) { |
462 | 48ff7a62 | Michael Roth | /* we spin on EOF for virtio-serial, so back off a bit. also,
|
463 | 48ff7a62 | Michael Roth | * dont close the connection in this case, it'll resume normal
|
464 | 48ff7a62 | Michael Roth | * operation when another process connects to host chardev
|
465 | 48ff7a62 | Michael Roth | */
|
466 | 48ff7a62 | Michael Roth | usleep(100*1000); |
467 | 48ff7a62 | Michael Roth | goto out_noclose;
|
468 | 48ff7a62 | Michael Roth | } |
469 | 48ff7a62 | Michael Roth | g_io_channel_unref(s->conn_channel); |
470 | 48ff7a62 | Michael Roth | s->conn_channel = NULL;
|
471 | 48ff7a62 | Michael Roth | out_noclose:
|
472 | 48ff7a62 | Michael Roth | return;
|
473 | 48ff7a62 | Michael Roth | } |
474 | 48ff7a62 | Michael Roth | |
475 | 48ff7a62 | Michael Roth | static void init_guest_agent(GAState *s) |
476 | 48ff7a62 | Michael Roth | { |
477 | 48ff7a62 | Michael Roth | struct termios tio;
|
478 | 48ff7a62 | Michael Roth | int ret, fd;
|
479 | 48ff7a62 | Michael Roth | |
480 | 48ff7a62 | Michael Roth | if (s->method == NULL) { |
481 | 48ff7a62 | Michael Roth | /* try virtio-serial as our default */
|
482 | 48ff7a62 | Michael Roth | s->method = "virtio-serial";
|
483 | 48ff7a62 | Michael Roth | } |
484 | 48ff7a62 | Michael Roth | |
485 | 48ff7a62 | Michael Roth | if (s->path == NULL) { |
486 | 48ff7a62 | Michael Roth | if (strcmp(s->method, "virtio-serial") != 0) { |
487 | 48ff7a62 | Michael Roth | g_critical("must specify a path for this channel");
|
488 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
489 | 48ff7a62 | Michael Roth | } |
490 | 48ff7a62 | Michael Roth | /* try the default path for the virtio-serial port */
|
491 | 48ff7a62 | Michael Roth | s->path = QGA_VIRTIO_PATH_DEFAULT; |
492 | 48ff7a62 | Michael Roth | } |
493 | 48ff7a62 | Michael Roth | |
494 | 48ff7a62 | Michael Roth | if (strcmp(s->method, "virtio-serial") == 0) { |
495 | 48ff7a62 | Michael Roth | s->virtio = true;
|
496 | 48ff7a62 | Michael Roth | fd = qemu_open(s->path, O_RDWR | O_NONBLOCK | O_ASYNC); |
497 | 48ff7a62 | Michael Roth | if (fd == -1) { |
498 | 48ff7a62 | Michael Roth | g_critical("error opening channel: %s", strerror(errno));
|
499 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
500 | 48ff7a62 | Michael Roth | } |
501 | 48ff7a62 | Michael Roth | ret = conn_channel_add(s, fd); |
502 | 48ff7a62 | Michael Roth | if (ret) {
|
503 | 48ff7a62 | Michael Roth | g_critical("error adding channel to main loop");
|
504 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
505 | 48ff7a62 | Michael Roth | } |
506 | 48ff7a62 | Michael Roth | } else if (strcmp(s->method, "isa-serial") == 0) { |
507 | 48ff7a62 | Michael Roth | fd = qemu_open(s->path, O_RDWR | O_NOCTTY); |
508 | 48ff7a62 | Michael Roth | if (fd == -1) { |
509 | 48ff7a62 | Michael Roth | g_critical("error opening channel: %s", strerror(errno));
|
510 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
511 | 48ff7a62 | Michael Roth | } |
512 | 48ff7a62 | Michael Roth | tcgetattr(fd, &tio); |
513 | 48ff7a62 | Michael Roth | /* set up serial port for non-canonical, dumb byte streaming */
|
514 | 48ff7a62 | Michael Roth | tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | |
515 | 48ff7a62 | Michael Roth | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | |
516 | 48ff7a62 | Michael Roth | IMAXBEL); |
517 | 48ff7a62 | Michael Roth | tio.c_oflag = 0;
|
518 | 48ff7a62 | Michael Roth | tio.c_lflag = 0;
|
519 | 48ff7a62 | Michael Roth | tio.c_cflag |= QGA_BAUDRATE_DEFAULT; |
520 | 48ff7a62 | Michael Roth | /* 1 available byte min or reads will block (we'll set non-blocking
|
521 | 48ff7a62 | Michael Roth | * elsewhere, else we have to deal with read()=0 instead)
|
522 | 48ff7a62 | Michael Roth | */
|
523 | 48ff7a62 | Michael Roth | tio.c_cc[VMIN] = 1;
|
524 | 48ff7a62 | Michael Roth | tio.c_cc[VTIME] = 0;
|
525 | 48ff7a62 | Michael Roth | /* flush everything waiting for read/xmit, it's garbage at this point */
|
526 | 48ff7a62 | Michael Roth | tcflush(fd, TCIFLUSH); |
527 | 48ff7a62 | Michael Roth | tcsetattr(fd, TCSANOW, &tio); |
528 | 48ff7a62 | Michael Roth | ret = conn_channel_add(s, fd); |
529 | 48ff7a62 | Michael Roth | if (ret) {
|
530 | 48ff7a62 | Michael Roth | g_error("error adding channel to main loop");
|
531 | 48ff7a62 | Michael Roth | } |
532 | 48ff7a62 | Michael Roth | } else if (strcmp(s->method, "unix-listen") == 0) { |
533 | 48ff7a62 | Michael Roth | fd = unix_listen(s->path, NULL, strlen(s->path));
|
534 | 48ff7a62 | Michael Roth | if (fd == -1) { |
535 | 48ff7a62 | Michael Roth | g_critical("error opening path: %s", strerror(errno));
|
536 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
537 | 48ff7a62 | Michael Roth | } |
538 | 48ff7a62 | Michael Roth | ret = listen_channel_add(s, fd, true);
|
539 | 48ff7a62 | Michael Roth | if (ret) {
|
540 | 48ff7a62 | Michael Roth | g_critical("error binding/listening to specified socket");
|
541 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
542 | 48ff7a62 | Michael Roth | } |
543 | 48ff7a62 | Michael Roth | } else {
|
544 | 48ff7a62 | Michael Roth | g_critical("unsupported channel method/type: %s", s->method);
|
545 | 48ff7a62 | Michael Roth | exit(EXIT_FAILURE); |
546 | 48ff7a62 | Michael Roth | } |
547 | 48ff7a62 | Michael Roth | |
548 | 48ff7a62 | Michael Roth | json_message_parser_init(&s->parser, process_event); |
549 | 48ff7a62 | Michael Roth | s->main_loop = g_main_loop_new(NULL, false); |
550 | 48ff7a62 | Michael Roth | } |
551 | 48ff7a62 | Michael Roth | |
552 | 48ff7a62 | Michael Roth | int main(int argc, char **argv) |
553 | 48ff7a62 | Michael Roth | { |
554 | abd6cf6d | Michael Roth | const char *sopt = "hVvdm:p:l:f:b:"; |
555 | 48ff7a62 | Michael Roth | const char *method = NULL, *path = NULL, *pidfile = QGA_PIDFILE_DEFAULT; |
556 | 48ff7a62 | Michael Roth | const struct option lopt[] = { |
557 | 48ff7a62 | Michael Roth | { "help", 0, NULL, 'h' }, |
558 | 48ff7a62 | Michael Roth | { "version", 0, NULL, 'V' }, |
559 | 48ff7a62 | Michael Roth | { "logfile", 0, NULL, 'l' }, |
560 | 48ff7a62 | Michael Roth | { "pidfile", 0, NULL, 'f' }, |
561 | 48ff7a62 | Michael Roth | { "verbose", 0, NULL, 'v' }, |
562 | 48ff7a62 | Michael Roth | { "method", 0, NULL, 'm' }, |
563 | 48ff7a62 | Michael Roth | { "path", 0, NULL, 'p' }, |
564 | 48ff7a62 | Michael Roth | { "daemonize", 0, NULL, 'd' }, |
565 | abd6cf6d | Michael Roth | { "blacklist", 0, NULL, 'b' }, |
566 | 48ff7a62 | Michael Roth | { NULL, 0, NULL, 0 } |
567 | 48ff7a62 | Michael Roth | }; |
568 | abd6cf6d | Michael Roth | int opt_ind = 0, ch, daemonize = 0, i, j, len; |
569 | 48ff7a62 | Michael Roth | GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; |
570 | 48ff7a62 | Michael Roth | FILE *log_file = stderr; |
571 | 48ff7a62 | Michael Roth | GAState *s; |
572 | 48ff7a62 | Michael Roth | |
573 | abd6cf6d | Michael Roth | module_call_init(MODULE_INIT_QAPI); |
574 | abd6cf6d | Michael Roth | |
575 | 48ff7a62 | Michael Roth | while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { |
576 | 48ff7a62 | Michael Roth | switch (ch) {
|
577 | 48ff7a62 | Michael Roth | case 'm': |
578 | 48ff7a62 | Michael Roth | method = optarg; |
579 | 48ff7a62 | Michael Roth | break;
|
580 | 48ff7a62 | Michael Roth | case 'p': |
581 | 48ff7a62 | Michael Roth | path = optarg; |
582 | 48ff7a62 | Michael Roth | break;
|
583 | 48ff7a62 | Michael Roth | case 'l': |
584 | 48ff7a62 | Michael Roth | log_file = fopen(optarg, "a");
|
585 | 48ff7a62 | Michael Roth | if (!log_file) {
|
586 | 48ff7a62 | Michael Roth | g_critical("unable to open specified log file: %s",
|
587 | 48ff7a62 | Michael Roth | strerror(errno)); |
588 | 48ff7a62 | Michael Roth | return EXIT_FAILURE;
|
589 | 48ff7a62 | Michael Roth | } |
590 | 48ff7a62 | Michael Roth | break;
|
591 | 48ff7a62 | Michael Roth | case 'f': |
592 | 48ff7a62 | Michael Roth | pidfile = optarg; |
593 | 48ff7a62 | Michael Roth | break;
|
594 | 48ff7a62 | Michael Roth | case 'v': |
595 | 48ff7a62 | Michael Roth | /* enable all log levels */
|
596 | 48ff7a62 | Michael Roth | log_level = G_LOG_LEVEL_MASK; |
597 | 48ff7a62 | Michael Roth | break;
|
598 | 48ff7a62 | Michael Roth | case 'V': |
599 | 48ff7a62 | Michael Roth | printf("QEMU Guest Agent %s\n", QGA_VERSION);
|
600 | 48ff7a62 | Michael Roth | return 0; |
601 | 48ff7a62 | Michael Roth | case 'd': |
602 | 48ff7a62 | Michael Roth | daemonize = 1;
|
603 | 48ff7a62 | Michael Roth | break;
|
604 | abd6cf6d | Michael Roth | case 'b': { |
605 | abd6cf6d | Michael Roth | char **list_head, **list;
|
606 | abd6cf6d | Michael Roth | if (*optarg == '?') { |
607 | abd6cf6d | Michael Roth | list_head = list = qmp_get_command_list(); |
608 | abd6cf6d | Michael Roth | while (*list != NULL) { |
609 | abd6cf6d | Michael Roth | printf("%s\n", *list);
|
610 | abd6cf6d | Michael Roth | g_free(*list); |
611 | abd6cf6d | Michael Roth | list++; |
612 | abd6cf6d | Michael Roth | } |
613 | abd6cf6d | Michael Roth | g_free(list_head); |
614 | abd6cf6d | Michael Roth | return 0; |
615 | abd6cf6d | Michael Roth | } |
616 | abd6cf6d | Michael Roth | for (j = 0, i = 0, len = strlen(optarg); i < len; i++) { |
617 | abd6cf6d | Michael Roth | if (optarg[i] == ',') { |
618 | abd6cf6d | Michael Roth | optarg[i] = 0;
|
619 | abd6cf6d | Michael Roth | qmp_disable_command(&optarg[j]); |
620 | abd6cf6d | Michael Roth | g_debug("disabling command: %s", &optarg[j]);
|
621 | abd6cf6d | Michael Roth | j = i + 1;
|
622 | abd6cf6d | Michael Roth | } |
623 | abd6cf6d | Michael Roth | } |
624 | abd6cf6d | Michael Roth | if (j < i) {
|
625 | abd6cf6d | Michael Roth | qmp_disable_command(&optarg[j]); |
626 | abd6cf6d | Michael Roth | g_debug("disabling command: %s", &optarg[j]);
|
627 | abd6cf6d | Michael Roth | } |
628 | abd6cf6d | Michael Roth | break;
|
629 | abd6cf6d | Michael Roth | } |
630 | 48ff7a62 | Michael Roth | case 'h': |
631 | 48ff7a62 | Michael Roth | usage(argv[0]);
|
632 | 48ff7a62 | Michael Roth | return 0; |
633 | 48ff7a62 | Michael Roth | case '?': |
634 | 48ff7a62 | Michael Roth | g_print("Unknown option, try '%s --help' for more information.\n",
|
635 | 48ff7a62 | Michael Roth | argv[0]);
|
636 | 48ff7a62 | Michael Roth | return EXIT_FAILURE;
|
637 | 48ff7a62 | Michael Roth | } |
638 | 48ff7a62 | Michael Roth | } |
639 | 48ff7a62 | Michael Roth | |
640 | 48ff7a62 | Michael Roth | if (daemonize) {
|
641 | 48ff7a62 | Michael Roth | g_debug("starting daemon");
|
642 | 48ff7a62 | Michael Roth | become_daemon(pidfile); |
643 | 48ff7a62 | Michael Roth | } |
644 | 48ff7a62 | Michael Roth | |
645 | 7267c094 | Anthony Liguori | s = g_malloc0(sizeof(GAState));
|
646 | 48ff7a62 | Michael Roth | s->conn_channel = NULL;
|
647 | 48ff7a62 | Michael Roth | s->path = path; |
648 | 48ff7a62 | Michael Roth | s->method = method; |
649 | 48ff7a62 | Michael Roth | s->log_file = log_file; |
650 | 48ff7a62 | Michael Roth | s->log_level = log_level; |
651 | 48ff7a62 | Michael Roth | g_log_set_default_handler(ga_log, s); |
652 | 48ff7a62 | Michael Roth | g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
|
653 | 48ff7a62 | Michael Roth | s->logging_enabled = true;
|
654 | e3d4d252 | Michael Roth | s->command_state = ga_command_state_new(); |
655 | e3d4d252 | Michael Roth | ga_command_state_init(s, s->command_state); |
656 | e3d4d252 | Michael Roth | ga_command_state_init_all(s->command_state); |
657 | 48ff7a62 | Michael Roth | ga_state = s; |
658 | 48ff7a62 | Michael Roth | |
659 | 48ff7a62 | Michael Roth | init_guest_agent(ga_state); |
660 | 48ff7a62 | Michael Roth | register_signal_handlers(); |
661 | 48ff7a62 | Michael Roth | |
662 | 48ff7a62 | Michael Roth | g_main_loop_run(ga_state->main_loop); |
663 | 48ff7a62 | Michael Roth | |
664 | e3d4d252 | Michael Roth | ga_command_state_cleanup_all(ga_state->command_state); |
665 | 48ff7a62 | Michael Roth | unlink(pidfile); |
666 | 48ff7a62 | Michael Roth | |
667 | 48ff7a62 | Michael Roth | return 0; |
668 | 48ff7a62 | Michael Roth | } |