]> git.proxmox.com Git - mirror_qemu.git/blame - qga/commands-posix.c
util: replace pipe()+cloexec with g_unix_open_pipe()
[mirror_qemu.git] / qga / commands-posix.c
CommitLineData
e3d4d252 1/*
42074a9d 2 * QEMU Guest Agent POSIX-specific command implementations
e3d4d252
MR
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
3424fc9f 8 * Michal Privoznik <mprivozn@redhat.com>
e3d4d252
MR
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
4459bf38 14#include "qemu/osdep.h"
e72c3f2e 15#include <sys/ioctl.h>
9848f797 16#include <sys/utsname.h>
2c02cbf6 17#include <sys/wait.h>
46d4c572 18#include <dirent.h>
dc03272d 19#include "guest-agent-core.h"
eb815e24 20#include "qga-qapi-commands.h"
e688df6b 21#include "qapi/error.h"
7b1b5d19 22#include "qapi/qmp/qerror.h"
1de7afc9
PB
23#include "qemu/queue.h"
24#include "qemu/host-utils.h"
12505396 25#include "qemu/sockets.h"
920639ca 26#include "qemu/base64.h"
f348b6d1 27#include "qemu/cutils.h"
5d3586b8 28#include "commands-common.h"
4eb36d40 29
e674605f
TG
30#ifdef HAVE_UTMPX
31#include <utmpx.h>
32#endif
33
4eb36d40 34#if defined(__linux__)
e3d4d252 35#include <mntent.h>
7006b9cf 36#include <linux/fs.h>
3424fc9f
MP
37#include <ifaddrs.h>
38#include <arpa/inet.h>
39#include <sys/socket.h>
40#include <net/if.h>
25b5ff1a 41#include <sys/statvfs.h>
e3d4d252 42
b616105a
TG
43#ifdef CONFIG_LIBUDEV
44#include <libudev.h>
45#endif
46
eab5fd59 47#ifdef FIFREEZE
e72c3f2e
MR
48#define CONFIG_FSFREEZE
49#endif
eab5fd59
PB
50#ifdef FITRIM
51#define CONFIG_FSTRIM
52#endif
e72c3f2e
MR
53#endif
54
77dbc81b 55static void ga_wait_child(pid_t pid, int *status, Error **errp)
d220a6df
LC
56{
57 pid_t rpid;
58
59 *status = 0;
60
61 do {
62 rpid = waitpid(pid, status, 0);
63 } while (rpid == -1 && errno == EINTR);
64
65 if (rpid == -1) {
77dbc81b
MA
66 error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
67 pid);
d220a6df
LC
68 return;
69 }
70
71 g_assert(rpid == pid);
72}
73
77dbc81b 74void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
e3d4d252 75{
e3d4d252 76 const char *shutdown_flag;
d220a6df
LC
77 Error *local_err = NULL;
78 pid_t pid;
3674838c 79 int status;
e3d4d252
MR
80
81 slog("guest-shutdown called, mode: %s", mode);
82 if (!has_mode || strcmp(mode, "powerdown") == 0) {
83 shutdown_flag = "-P";
84 } else if (strcmp(mode, "halt") == 0) {
85 shutdown_flag = "-H";
86 } else if (strcmp(mode, "reboot") == 0) {
87 shutdown_flag = "-r";
88 } else {
77dbc81b 89 error_setg(errp,
d220a6df 90 "mode is invalid (valid values are: halt|powerdown|reboot");
e3d4d252
MR
91 return;
92 }
93
d5dd3498
LC
94 pid = fork();
95 if (pid == 0) {
e3d4d252
MR
96 /* child, start the shutdown */
97 setsid();
3674838c
LC
98 reopen_fd_to_null(0);
99 reopen_fd_to_null(1);
100 reopen_fd_to_null(2);
e3d4d252 101
fcc41961
MAL
102 execl("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0",
103 "hypervisor initiated shutdown", (char *)NULL);
3674838c 104 _exit(EXIT_FAILURE);
d5dd3498 105 } else if (pid < 0) {
77dbc81b 106 error_setg_errno(errp, errno, "failed to create child process");
d220a6df 107 return;
e3d4d252 108 }
d5dd3498 109
d220a6df 110 ga_wait_child(pid, &status, &local_err);
84d18f06 111 if (local_err) {
77dbc81b 112 error_propagate(errp, local_err);
d220a6df
LC
113 return;
114 }
115
116 if (!WIFEXITED(status)) {
77dbc81b 117 error_setg(errp, "child process has terminated abnormally");
d220a6df
LC
118 return;
119 }
120
121 if (WEXITSTATUS(status)) {
77dbc81b 122 error_setg(errp, "child process has failed to shutdown");
d5dd3498
LC
123 return;
124 }
125
085d8134 126 /* succeeded */
e3d4d252
MR
127}
128
2c958923 129void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
a1bca57f
LL
130{
131 int ret;
132 int status;
133 pid_t pid;
134 Error *local_err = NULL;
135 struct timeval tv;
5c6096e5
CH
136 static const char hwclock_path[] = "/sbin/hwclock";
137 static int hwclock_available = -1;
138
139 if (hwclock_available < 0) {
140 hwclock_available = (access(hwclock_path, X_OK) == 0);
141 }
142
143 if (!hwclock_available) {
144 error_setg(errp, QERR_UNSUPPORTED);
145 return;
146 }
a1bca57f 147
2c958923
MP
148 /* If user has passed a time, validate and set it. */
149 if (has_time) {
00d2f370
MAL
150 GDate date = { 0, };
151
2c958923
MP
152 /* year-2038 will overflow in case time_t is 32bit */
153 if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
154 error_setg(errp, "Time %" PRId64 " is too large", time_ns);
155 return;
156 }
157
158 tv.tv_sec = time_ns / 1000000000;
159 tv.tv_usec = (time_ns % 1000000000) / 1000;
00d2f370
MAL
160 g_date_set_time_t(&date, tv.tv_sec);
161 if (date.year < 1970 || date.year >= 2070) {
162 error_setg_errno(errp, errno, "Invalid time");
163 return;
164 }
2c958923
MP
165
166 ret = settimeofday(&tv, NULL);
167 if (ret < 0) {
168 error_setg_errno(errp, errno, "Failed to set time to guest");
169 return;
170 }
a1bca57f
LL
171 }
172
2c958923
MP
173 /* Now, if user has passed a time to set and the system time is set, we
174 * just need to synchronize the hardware clock. However, if no time was
175 * passed, user is requesting the opposite: set the system time from the
1634df56 176 * hardware clock (RTC). */
a1bca57f
LL
177 pid = fork();
178 if (pid == 0) {
179 setsid();
180 reopen_fd_to_null(0);
181 reopen_fd_to_null(1);
182 reopen_fd_to_null(2);
183
2c958923
MP
184 /* Use '/sbin/hwclock -w' to set RTC from the system time,
185 * or '/sbin/hwclock -s' to set the system time from RTC. */
fcc41961 186 execl(hwclock_path, "hwclock", has_time ? "-w" : "-s", NULL);
a1bca57f
LL
187 _exit(EXIT_FAILURE);
188 } else if (pid < 0) {
189 error_setg_errno(errp, errno, "failed to create child process");
190 return;
191 }
192
193 ga_wait_child(pid, &status, &local_err);
84d18f06 194 if (local_err) {
a1bca57f
LL
195 error_propagate(errp, local_err);
196 return;
197 }
198
199 if (!WIFEXITED(status)) {
200 error_setg(errp, "child process has terminated abnormally");
201 return;
202 }
203
204 if (WEXITSTATUS(status)) {
205 error_setg(errp, "hwclock failed to set hardware clock to system time");
206 return;
207 }
208}
209
895b00f6
MAL
210typedef enum {
211 RW_STATE_NEW,
212 RW_STATE_READING,
213 RW_STATE_WRITING,
214} RwState;
215
5d3586b8 216struct GuestFileHandle {
e3d4d252
MR
217 uint64_t id;
218 FILE *fh;
895b00f6 219 RwState state;
e3d4d252 220 QTAILQ_ENTRY(GuestFileHandle) next;
5d3586b8 221};
e3d4d252
MR
222
223static struct {
224 QTAILQ_HEAD(, GuestFileHandle) filehandles;
b4fe97c8
DL
225} guest_file_state = {
226 .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
227};
e3d4d252 228
39097daf 229static int64_t guest_file_handle_add(FILE *fh, Error **errp)
e3d4d252
MR
230{
231 GuestFileHandle *gfh;
39097daf
MR
232 int64_t handle;
233
234 handle = ga_get_fd_handle(ga_state, errp);
a903f40c
MA
235 if (handle < 0) {
236 return -1;
39097daf 237 }
e3d4d252 238
f3a06403 239 gfh = g_new0(GuestFileHandle, 1);
39097daf 240 gfh->id = handle;
e3d4d252
MR
241 gfh->fh = fh;
242 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
39097daf
MR
243
244 return handle;
e3d4d252
MR
245}
246
5d3586b8 247GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
e3d4d252
MR
248{
249 GuestFileHandle *gfh;
250
251 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
252 {
253 if (gfh->id == id) {
254 return gfh;
255 }
256 }
257
77dbc81b 258 error_setg(errp, "handle '%" PRId64 "' has not been found", id);
e3d4d252
MR
259 return NULL;
260}
261
c689b4f1
LE
262typedef const char * const ccpc;
263
8fe6bbca
LE
264#ifndef O_BINARY
265#define O_BINARY 0
266#endif
267
c689b4f1
LE
268/* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
269static const struct {
270 ccpc *forms;
271 int oflag_base;
272} guest_file_open_modes[] = {
8fe6bbca
LE
273 { (ccpc[]){ "r", NULL }, O_RDONLY },
274 { (ccpc[]){ "rb", NULL }, O_RDONLY | O_BINARY },
275 { (ccpc[]){ "w", NULL }, O_WRONLY | O_CREAT | O_TRUNC },
276 { (ccpc[]){ "wb", NULL }, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY },
277 { (ccpc[]){ "a", NULL }, O_WRONLY | O_CREAT | O_APPEND },
278 { (ccpc[]){ "ab", NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
279 { (ccpc[]){ "r+", NULL }, O_RDWR },
280 { (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR | O_BINARY },
281 { (ccpc[]){ "w+", NULL }, O_RDWR | O_CREAT | O_TRUNC },
282 { (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR | O_CREAT | O_TRUNC | O_BINARY },
283 { (ccpc[]){ "a+", NULL }, O_RDWR | O_CREAT | O_APPEND },
284 { (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR | O_CREAT | O_APPEND | O_BINARY }
c689b4f1
LE
285};
286
287static int
77dbc81b 288find_open_flag(const char *mode_str, Error **errp)
c689b4f1
LE
289{
290 unsigned mode;
291
292 for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
293 ccpc *form;
294
295 form = guest_file_open_modes[mode].forms;
296 while (*form != NULL && strcmp(*form, mode_str) != 0) {
297 ++form;
298 }
299 if (*form != NULL) {
300 break;
301 }
302 }
303
304 if (mode == ARRAY_SIZE(guest_file_open_modes)) {
77dbc81b 305 error_setg(errp, "invalid file open mode '%s'", mode_str);
c689b4f1
LE
306 return -1;
307 }
308 return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
309}
310
311#define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
312 S_IRGRP | S_IWGRP | \
313 S_IROTH | S_IWOTH)
314
315static FILE *
77dbc81b 316safe_open_or_create(const char *path, const char *mode, Error **errp)
c689b4f1
LE
317{
318 Error *local_err = NULL;
319 int oflag;
320
321 oflag = find_open_flag(mode, &local_err);
322 if (local_err == NULL) {
323 int fd;
324
325 /* If the caller wants / allows creation of a new file, we implement it
326 * with a two step process: open() + (open() / fchmod()).
327 *
328 * First we insist on creating the file exclusively as a new file. If
329 * that succeeds, we're free to set any file-mode bits on it. (The
330 * motivation is that we want to set those file-mode bits independently
331 * of the current umask.)
332 *
333 * If the exclusive creation fails because the file already exists
334 * (EEXIST is not possible for any other reason), we just attempt to
335 * open the file, but in this case we won't be allowed to change the
336 * file-mode bits on the preexistent file.
337 *
338 * The pathname should never disappear between the two open()s in
339 * practice. If it happens, then someone very likely tried to race us.
340 * In this case just go ahead and report the ENOENT from the second
341 * open() to the caller.
342 *
343 * If the caller wants to open a preexistent file, then the first
344 * open() is decisive and its third argument is ignored, and the second
345 * open() and the fchmod() are never called.
346 */
347 fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
348 if (fd == -1 && errno == EEXIST) {
349 oflag &= ~(unsigned)O_CREAT;
350 fd = open(path, oflag);
351 }
352
353 if (fd == -1) {
354 error_setg_errno(&local_err, errno, "failed to open file '%s' "
355 "(mode: '%s')", path, mode);
356 } else {
357 qemu_set_cloexec(fd);
358
359 if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
360 error_setg_errno(&local_err, errno, "failed to set permission "
361 "0%03o on new file '%s' (mode: '%s')",
362 (unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
363 } else {
364 FILE *f;
365
366 f = fdopen(fd, mode);
367 if (f == NULL) {
368 error_setg_errno(&local_err, errno, "failed to associate "
369 "stdio stream with file descriptor %d, "
370 "file '%s' (mode: '%s')", fd, path, mode);
371 } else {
372 return f;
373 }
374 }
375
376 close(fd);
2b720018
LE
377 if (oflag & O_CREAT) {
378 unlink(path);
379 }
c689b4f1
LE
380 }
381 }
382
77dbc81b 383 error_propagate(errp, local_err);
c689b4f1
LE
384 return NULL;
385}
386
77dbc81b
MA
387int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
388 Error **errp)
e3d4d252
MR
389{
390 FILE *fh;
c689b4f1 391 Error *local_err = NULL;
85b6f6f5 392 int64_t handle;
e3d4d252
MR
393
394 if (!has_mode) {
395 mode = "r";
396 }
397 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
c689b4f1
LE
398 fh = safe_open_or_create(path, mode, &local_err);
399 if (local_err != NULL) {
77dbc81b 400 error_propagate(errp, local_err);
e3d4d252
MR
401 return -1;
402 }
403
404 /* set fd non-blocking to avoid common use cases (like reading from a
405 * named pipe) from hanging the agent
406 */
12505396 407 qemu_set_nonblock(fileno(fh));
e3d4d252 408
77dbc81b 409 handle = guest_file_handle_add(fh, errp);
a903f40c 410 if (handle < 0) {
39097daf
MR
411 fclose(fh);
412 return -1;
413 }
414
d607a523 415 slog("guest-file-open, handle: %" PRId64, handle);
39097daf 416 return handle;
e3d4d252
MR
417}
418
77dbc81b 419void qmp_guest_file_close(int64_t handle, Error **errp)
e3d4d252 420{
77dbc81b 421 GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
e3d4d252
MR
422 int ret;
423
d607a523 424 slog("guest-file-close called, handle: %" PRId64, handle);
e3d4d252 425 if (!gfh) {
e3d4d252
MR
426 return;
427 }
428
429 ret = fclose(gfh->fh);
3ac4b7c5 430 if (ret == EOF) {
77dbc81b 431 error_setg_errno(errp, errno, "failed to close handle");
e3d4d252
MR
432 return;
433 }
434
435 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
7267c094 436 g_free(gfh);
e3d4d252
MR
437}
438
ead83a13
PMD
439GuestFileRead *guest_file_read_unsafe(GuestFileHandle *gfh,
440 int64_t count, Error **errp)
e3d4d252 441{
e3d4d252
MR
442 GuestFileRead *read_data = NULL;
443 guchar *buf;
ead83a13 444 FILE *fh = gfh->fh;
e3d4d252
MR
445 size_t read_count;
446
895b00f6
MAL
447 /* explicitly flush when switching from writing to reading */
448 if (gfh->state == RW_STATE_WRITING) {
449 int ret = fflush(fh);
450 if (ret == EOF) {
451 error_setg_errno(errp, errno, "failed to flush file");
452 return NULL;
453 }
454 gfh->state = RW_STATE_NEW;
455 }
456
0697e9ed 457 buf = g_malloc0(count + 1);
e3d4d252
MR
458 read_count = fread(buf, 1, count, fh);
459 if (ferror(fh)) {
77dbc81b 460 error_setg_errno(errp, errno, "failed to read file");
e3d4d252
MR
461 } else {
462 buf[read_count] = 0;
f3a06403 463 read_data = g_new0(GuestFileRead, 1);
e3d4d252
MR
464 read_data->count = read_count;
465 read_data->eof = feof(fh);
466 if (read_count) {
467 read_data->buf_b64 = g_base64_encode(buf, read_count);
468 }
895b00f6 469 gfh->state = RW_STATE_READING;
e3d4d252 470 }
7267c094 471 g_free(buf);
e3d4d252
MR
472 clearerr(fh);
473
474 return read_data;
475}
476
477GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
77dbc81b
MA
478 bool has_count, int64_t count,
479 Error **errp)
e3d4d252
MR
480{
481 GuestFileWrite *write_data = NULL;
482 guchar *buf;
483 gsize buf_len;
484 int write_count;
77dbc81b 485 GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
e3d4d252
MR
486 FILE *fh;
487
488 if (!gfh) {
e3d4d252
MR
489 return NULL;
490 }
491
492 fh = gfh->fh;
895b00f6
MAL
493
494 if (gfh->state == RW_STATE_READING) {
495 int ret = fseek(fh, 0, SEEK_CUR);
496 if (ret == -1) {
497 error_setg_errno(errp, errno, "failed to seek file");
498 return NULL;
499 }
500 gfh->state = RW_STATE_NEW;
501 }
502
920639ca
DB
503 buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
504 if (!buf) {
505 return NULL;
506 }
e3d4d252
MR
507
508 if (!has_count) {
509 count = buf_len;
510 } else if (count < 0 || count > buf_len) {
77dbc81b 511 error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
db3edb66 512 count);
7267c094 513 g_free(buf);
e3d4d252
MR
514 return NULL;
515 }
516
517 write_count = fwrite(buf, 1, count, fh);
518 if (ferror(fh)) {
77dbc81b 519 error_setg_errno(errp, errno, "failed to write to file");
d607a523 520 slog("guest-file-write failed, handle: %" PRId64, handle);
e3d4d252 521 } else {
f3a06403 522 write_data = g_new0(GuestFileWrite, 1);
e3d4d252
MR
523 write_data->count = write_count;
524 write_data->eof = feof(fh);
895b00f6 525 gfh->state = RW_STATE_WRITING;
e3d4d252 526 }
7267c094 527 g_free(buf);
e3d4d252
MR
528 clearerr(fh);
529
530 return write_data;
531}
532
533struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
0b4b4938
EB
534 GuestFileWhence *whence_code,
535 Error **errp)
e3d4d252 536{
77dbc81b 537 GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
e3d4d252
MR
538 GuestFileSeek *seek_data = NULL;
539 FILE *fh;
540 int ret;
0a982b1b 541 int whence;
0b4b4938 542 Error *err = NULL;
e3d4d252
MR
543
544 if (!gfh) {
e3d4d252
MR
545 return NULL;
546 }
547
0a982b1b 548 /* We stupidly exposed 'whence':'int' in our qapi */
0b4b4938
EB
549 whence = ga_parse_whence(whence_code, &err);
550 if (err) {
551 error_propagate(errp, err);
0a982b1b
EB
552 return NULL;
553 }
554
e3d4d252
MR
555 fh = gfh->fh;
556 ret = fseek(fh, offset, whence);
557 if (ret == -1) {
77dbc81b 558 error_setg_errno(errp, errno, "failed to seek file");
895b00f6
MAL
559 if (errno == ESPIPE) {
560 /* file is non-seekable, stdio shouldn't be buffering anyways */
561 gfh->state = RW_STATE_NEW;
562 }
e3d4d252 563 } else {
10b7c5dd 564 seek_data = g_new0(GuestFileSeek, 1);
e3d4d252
MR
565 seek_data->position = ftell(fh);
566 seek_data->eof = feof(fh);
895b00f6 567 gfh->state = RW_STATE_NEW;
e3d4d252
MR
568 }
569 clearerr(fh);
570
571 return seek_data;
572}
573
77dbc81b 574void qmp_guest_file_flush(int64_t handle, Error **errp)
e3d4d252 575{
77dbc81b 576 GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
e3d4d252
MR
577 FILE *fh;
578 int ret;
579
580 if (!gfh) {
e3d4d252
MR
581 return;
582 }
583
584 fh = gfh->fh;
585 ret = fflush(fh);
586 if (ret == EOF) {
77dbc81b 587 error_setg_errno(errp, errno, "failed to flush file");
895b00f6
MAL
588 } else {
589 gfh->state = RW_STATE_NEW;
e3d4d252
MR
590 }
591}
592
e72c3f2e
MR
593/* linux-specific implementations. avoid this if at all possible. */
594#if defined(__linux__)
595
eab5fd59 596#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
af02203f 597typedef struct FsMount {
e3d4d252
MR
598 char *dirname;
599 char *devtype;
46d4c572 600 unsigned int devmajor, devminor;
af02203f
PB
601 QTAILQ_ENTRY(FsMount) next;
602} FsMount;
e3d4d252 603
e5d9adbd 604typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
9e8aded4 605
af02203f 606static void free_fs_mount_list(FsMountList *mounts)
9e8aded4 607{
af02203f 608 FsMount *mount, *temp;
9e8aded4
MR
609
610 if (!mounts) {
611 return;
612 }
613
614 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
615 QTAILQ_REMOVE(mounts, mount, next);
616 g_free(mount->dirname);
617 g_free(mount->devtype);
618 g_free(mount);
619 }
620}
621
46d4c572
TS
622static int dev_major_minor(const char *devpath,
623 unsigned int *devmajor, unsigned int *devminor)
624{
625 struct stat st;
626
627 *devmajor = 0;
628 *devminor = 0;
629
630 if (stat(devpath, &st) < 0) {
631 slog("failed to stat device file '%s': %s", devpath, strerror(errno));
632 return -1;
633 }
634 if (S_ISDIR(st.st_mode)) {
635 /* It is bind mount */
636 return -2;
637 }
638 if (S_ISBLK(st.st_mode)) {
639 *devmajor = major(st.st_rdev);
640 *devminor = minor(st.st_rdev);
641 return 0;
642 }
643 return -1;
644}
645
e3d4d252
MR
646/*
647 * Walk the mount table and build a list of local file systems
648 */
46d4c572 649static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
e3d4d252
MR
650{
651 struct mntent *ment;
af02203f 652 FsMount *mount;
9e2fa418 653 char const *mtab = "/proc/self/mounts";
e3d4d252 654 FILE *fp;
46d4c572 655 unsigned int devmajor, devminor;
e3d4d252 656
e3d4d252
MR
657 fp = setmntent(mtab, "r");
658 if (!fp) {
77dbc81b 659 error_setg(errp, "failed to open mtab file: '%s'", mtab);
261551d1 660 return;
e3d4d252
MR
661 }
662
663 while ((ment = getmntent(fp))) {
664 /*
665 * An entry which device name doesn't start with a '/' is
666 * either a dummy file system or a network file system.
667 * Add special handling for smbfs and cifs as is done by
668 * coreutils as well.
669 */
670 if ((ment->mnt_fsname[0] != '/') ||
671 (strcmp(ment->mnt_type, "smbfs") == 0) ||
672 (strcmp(ment->mnt_type, "cifs") == 0)) {
673 continue;
674 }
46d4c572
TS
675 if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) {
676 /* Skip bind mounts */
677 continue;
678 }
e3d4d252 679
f3a06403 680 mount = g_new0(FsMount, 1);
7267c094
AL
681 mount->dirname = g_strdup(ment->mnt_dir);
682 mount->devtype = g_strdup(ment->mnt_type);
46d4c572
TS
683 mount->devmajor = devmajor;
684 mount->devminor = devminor;
e3d4d252 685
9e8aded4 686 QTAILQ_INSERT_TAIL(mounts, mount, next);
e3d4d252
MR
687 }
688
689 endmntent(fp);
e3d4d252 690}
46d4c572
TS
691
692static void decode_mntname(char *name, int len)
693{
694 int i, j = 0;
695 for (i = 0; i <= len; i++) {
696 if (name[i] != '\\') {
697 name[j++] = name[i];
698 } else if (name[i + 1] == '\\') {
699 name[j++] = '\\';
700 i++;
701 } else if (name[i + 1] >= '0' && name[i + 1] <= '3' &&
702 name[i + 2] >= '0' && name[i + 2] <= '7' &&
703 name[i + 3] >= '0' && name[i + 3] <= '7') {
704 name[j++] = (name[i + 1] - '0') * 64 +
705 (name[i + 2] - '0') * 8 +
706 (name[i + 3] - '0');
707 i += 3;
708 } else {
709 name[j++] = name[i];
710 }
711 }
712}
713
714static void build_fs_mount_list(FsMountList *mounts, Error **errp)
715{
716 FsMount *mount;
717 char const *mountinfo = "/proc/self/mountinfo";
718 FILE *fp;
719 char *line = NULL, *dash;
720 size_t n;
721 char check;
722 unsigned int devmajor, devminor;
723 int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
724
725 fp = fopen(mountinfo, "r");
726 if (!fp) {
727 build_fs_mount_list_from_mtab(mounts, errp);
728 return;
729 }
730
731 while (getline(&line, &n, fp) != -1) {
732 ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c",
733 &devmajor, &devminor, &dir_s, &dir_e, &check);
734 if (ret < 3) {
735 continue;
736 }
737 dash = strstr(line + dir_e, " - ");
738 if (!dash) {
739 continue;
740 }
741 ret = sscanf(dash, " - %n%*s%n %n%*s%n%c",
742 &type_s, &type_e, &dev_s, &dev_e, &check);
743 if (ret < 1) {
744 continue;
745 }
746 line[dir_e] = 0;
747 dash[type_e] = 0;
748 dash[dev_e] = 0;
749 decode_mntname(line + dir_s, dir_e - dir_s);
750 decode_mntname(dash + dev_s, dev_e - dev_s);
751 if (devmajor == 0) {
752 /* btrfs reports major number = 0 */
753 if (strcmp("btrfs", dash + type_s) != 0 ||
754 dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) {
755 continue;
756 }
757 }
758
f3a06403 759 mount = g_new0(FsMount, 1);
46d4c572
TS
760 mount->dirname = g_strdup(line + dir_s);
761 mount->devtype = g_strdup(dash + type_s);
762 mount->devmajor = devmajor;
763 mount->devminor = devminor;
764
765 QTAILQ_INSERT_TAIL(mounts, mount, next);
766 }
767 free(line);
768
769 fclose(fp);
770}
eab5fd59
PB
771#endif
772
773#if defined(CONFIG_FSFREEZE)
e3d4d252 774
46d4c572
TS
775static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
776{
777 char *path;
778 char *dpath;
779 char *driver = NULL;
780 char buf[PATH_MAX];
781 ssize_t len;
782
783 path = g_strndup(syspath, pathlen);
784 dpath = g_strdup_printf("%s/driver", path);
785 len = readlink(dpath, buf, sizeof(buf) - 1);
786 if (len != -1) {
787 buf[len] = 0;
3e015d81 788 driver = g_path_get_basename(buf);
46d4c572
TS
789 }
790 g_free(dpath);
791 g_free(path);
792 return driver;
793}
794
795static int compare_uint(const void *_a, const void *_b)
796{
797 unsigned int a = *(unsigned int *)_a;
798 unsigned int b = *(unsigned int *)_b;
799
800 return a < b ? -1 : a > b ? 1 : 0;
801}
802
803/* Walk the specified sysfs and build a sorted list of host or ata numbers */
804static int build_hosts(char const *syspath, char const *host, bool ata,
805 unsigned int *hosts, int hosts_max, Error **errp)
806{
807 char *path;
808 DIR *dir;
809 struct dirent *entry;
810 int i = 0;
811
812 path = g_strndup(syspath, host - syspath);
813 dir = opendir(path);
814 if (!dir) {
815 error_setg_errno(errp, errno, "opendir(\"%s\")", path);
816 g_free(path);
817 return -1;
818 }
819
820 while (i < hosts_max) {
821 entry = readdir(dir);
822 if (!entry) {
823 break;
824 }
825 if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
826 ++i;
827 } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
828 ++i;
829 }
830 }
831
832 qsort(hosts, i, sizeof(hosts[0]), compare_uint);
833
834 g_free(path);
835 closedir(dir);
836 return i;
837}
838
d9fe4f0f
TH
839/*
840 * Store disk device info for devices on the PCI bus.
841 * Returns true if information has been stored, or false for failure.
842 */
843static bool build_guest_fsinfo_for_pci_dev(char const *syspath,
844 GuestDiskAddress *disk,
845 Error **errp)
46d4c572
TS
846{
847 unsigned int pci[4], host, hosts[8], tgt[3];
848 int i, nhosts = 0, pcilen;
d9fe4f0f 849 GuestPCIAddress *pciaddr = disk->pci_controller;
46d4c572
TS
850 bool has_ata = false, has_host = false, has_tgt = false;
851 char *p, *q, *driver = NULL;
d9fe4f0f 852 bool ret = false;
46d4c572
TS
853
854 p = strstr(syspath, "/devices/pci");
855 if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
856 pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
743c71d0 857 g_debug("only pci device is supported: sysfs path '%s'", syspath);
d9fe4f0f 858 return false;
46d4c572
TS
859 }
860
743c71d0
MAL
861 p += 12 + pcilen;
862 while (true) {
863 driver = get_pci_driver(syspath, p - syspath, errp);
864 if (driver && (g_str_equal(driver, "ata_piix") ||
865 g_str_equal(driver, "sym53c8xx") ||
866 g_str_equal(driver, "virtio-pci") ||
867 g_str_equal(driver, "ahci"))) {
868 break;
869 }
870
bb23a736 871 g_free(driver);
743c71d0
MAL
872 if (sscanf(p, "/%x:%x:%x.%x%n",
873 pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
874 p += pcilen;
875 continue;
876 }
877
878 g_debug("unsupported driver or sysfs path '%s'", syspath);
d9fe4f0f 879 return false;
46d4c572
TS
880 }
881
882 p = strstr(syspath, "/target");
883 if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
884 tgt, tgt + 1, tgt + 2) == 3) {
885 has_tgt = true;
886 }
887
888 p = strstr(syspath, "/ata");
889 if (p) {
890 q = p + 4;
891 has_ata = true;
892 } else {
893 p = strstr(syspath, "/host");
894 q = p + 5;
895 }
896 if (p && sscanf(q, "%u", &host) == 1) {
897 has_host = true;
898 nhosts = build_hosts(syspath, p, has_ata, hosts,
01a6df1b 899 ARRAY_SIZE(hosts), errp);
46d4c572
TS
900 if (nhosts < 0) {
901 goto cleanup;
902 }
903 }
904
46d4c572
TS
905 pciaddr->domain = pci[0];
906 pciaddr->bus = pci[1];
907 pciaddr->slot = pci[2];
908 pciaddr->function = pci[3];
909
46d4c572
TS
910 if (strcmp(driver, "ata_piix") == 0) {
911 /* a host per ide bus, target*:0:<unit>:0 */
912 if (!has_host || !has_tgt) {
913 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
914 goto cleanup;
915 }
916 for (i = 0; i < nhosts; i++) {
917 if (host == hosts[i]) {
918 disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
919 disk->bus = i;
920 disk->unit = tgt[1];
921 break;
922 }
923 }
924 if (i >= nhosts) {
925 g_debug("no host for '%s' (driver '%s')", syspath, driver);
926 goto cleanup;
927 }
928 } else if (strcmp(driver, "sym53c8xx") == 0) {
929 /* scsi(LSI Logic): target*:0:<unit>:0 */
930 if (!has_tgt) {
931 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
932 goto cleanup;
933 }
934 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
935 disk->unit = tgt[1];
936 } else if (strcmp(driver, "virtio-pci") == 0) {
937 if (has_tgt) {
938 /* virtio-scsi: target*:0:0:<unit> */
939 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
940 disk->unit = tgt[2];
941 } else {
942 /* virtio-blk: 1 disk per 1 device */
943 disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
944 }
945 } else if (strcmp(driver, "ahci") == 0) {
946 /* ahci: 1 host per 1 unit */
947 if (!has_host || !has_tgt) {
948 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
949 goto cleanup;
950 }
951 for (i = 0; i < nhosts; i++) {
952 if (host == hosts[i]) {
953 disk->unit = i;
954 disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
955 break;
956 }
957 }
958 if (i >= nhosts) {
959 g_debug("no host for '%s' (driver '%s')", syspath, driver);
960 goto cleanup;
961 }
962 } else {
963 g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
964 goto cleanup;
965 }
966
d9fe4f0f 967 ret = true;
46d4c572
TS
968
969cleanup:
46d4c572 970 g_free(driver);
d9fe4f0f
TH
971 return ret;
972}
973
23843c12
TH
974/*
975 * Store disk device info for non-PCI virtio devices (for example s390x
976 * channel I/O devices). Returns true if information has been stored, or
977 * false for failure.
978 */
979static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath,
980 GuestDiskAddress *disk,
981 Error **errp)
982{
983 unsigned int tgt[3];
984 char *p;
985
986 if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) {
987 g_debug("Unsupported virtio device '%s'", syspath);
988 return false;
989 }
990
991 p = strstr(syspath, "/target");
992 if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
993 &tgt[0], &tgt[1], &tgt[2]) == 3) {
994 /* virtio-scsi: target*:0:<target>:<unit> */
995 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
996 disk->bus = tgt[0];
997 disk->target = tgt[1];
998 disk->unit = tgt[2];
999 } else {
1000 /* virtio-blk: 1 disk per 1 device */
1001 disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
1002 }
1003
1004 return true;
1005}
1006
5b723a5d
TH
1007/*
1008 * Store disk device info for CCW devices (s390x channel I/O devices).
1009 * Returns true if information has been stored, or false for failure.
1010 */
1011static bool build_guest_fsinfo_for_ccw_dev(char const *syspath,
1012 GuestDiskAddress *disk,
1013 Error **errp)
1014{
1015 unsigned int cssid, ssid, subchno, devno;
1016 char *p;
1017
1018 p = strstr(syspath, "/devices/css");
1019 if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/",
1020 &cssid, &ssid, &subchno, &devno) < 4) {
1021 g_debug("could not parse ccw device sysfs path: %s", syspath);
1022 return false;
1023 }
1024
1025 disk->has_ccw_address = true;
1026 disk->ccw_address = g_new0(GuestCCWAddress, 1);
1027 disk->ccw_address->cssid = cssid;
1028 disk->ccw_address->ssid = ssid;
1029 disk->ccw_address->subchno = subchno;
1030 disk->ccw_address->devno = devno;
1031
1032 if (strstr(p, "/virtio")) {
1033 build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
1034 }
1035
1036 return true;
1037}
1038
d9fe4f0f
TH
1039/* Store disk device info specified by @sysfs into @fs */
1040static void build_guest_fsinfo_for_real_device(char const *syspath,
1041 GuestFilesystemInfo *fs,
1042 Error **errp)
1043{
1044 GuestDiskAddress *disk;
1045 GuestPCIAddress *pciaddr;
d9fe4f0f 1046 bool has_hwinf;
43dadc43
TH
1047#ifdef CONFIG_LIBUDEV
1048 struct udev *udev = NULL;
1049 struct udev_device *udevice = NULL;
1050#endif
d9fe4f0f
TH
1051
1052 pciaddr = g_new0(GuestPCIAddress, 1);
43dadc43
TH
1053 pciaddr->domain = -1; /* -1 means field is invalid */
1054 pciaddr->bus = -1;
1055 pciaddr->slot = -1;
1056 pciaddr->function = -1;
d9fe4f0f
TH
1057
1058 disk = g_new0(GuestDiskAddress, 1);
1059 disk->pci_controller = pciaddr;
43dadc43 1060 disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN;
d9fe4f0f 1061
43dadc43
TH
1062#ifdef CONFIG_LIBUDEV
1063 udev = udev_new();
1064 udevice = udev_device_new_from_syspath(udev, syspath);
1065 if (udev == NULL || udevice == NULL) {
1066 g_debug("failed to query udev");
1067 } else {
1068 const char *devnode, *serial;
1069 devnode = udev_device_get_devnode(udevice);
1070 if (devnode != NULL) {
1071 disk->dev = g_strdup(devnode);
1072 disk->has_dev = true;
1073 }
1074 serial = udev_device_get_property_value(udevice, "ID_SERIAL");
1075 if (serial != NULL && *serial != 0) {
1076 disk->serial = g_strdup(serial);
1077 disk->has_serial = true;
1078 }
1079 }
1080
1081 udev_unref(udev);
1082 udev_device_unref(udevice);
1083#endif
1084
23843c12
TH
1085 if (strstr(syspath, "/devices/pci")) {
1086 has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp);
5b723a5d
TH
1087 } else if (strstr(syspath, "/devices/css")) {
1088 has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp);
23843c12
TH
1089 } else if (strstr(syspath, "/virtio")) {
1090 has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
1091 } else {
1092 g_debug("Unsupported device type for '%s'", syspath);
1093 has_hwinf = false;
1094 }
d9fe4f0f 1095
43dadc43 1096 if (has_hwinf || disk->has_dev || disk->has_serial) {
54aa3de7 1097 QAPI_LIST_PREPEND(fs->disk, disk);
d9fe4f0f 1098 } else {
54aa3de7 1099 qapi_free_GuestDiskAddress(disk);
d9fe4f0f 1100 }
46d4c572
TS
1101}
1102
1103static void build_guest_fsinfo_for_device(char const *devpath,
1104 GuestFilesystemInfo *fs,
1105 Error **errp);
1106
1107/* Store a list of slave devices of virtual volume specified by @syspath into
1108 * @fs */
1109static void build_guest_fsinfo_for_virtual_device(char const *syspath,
1110 GuestFilesystemInfo *fs,
1111 Error **errp)
1112{
292743d9 1113 Error *err = NULL;
46d4c572
TS
1114 DIR *dir;
1115 char *dirpath;
e668d1b8 1116 struct dirent *entry;
46d4c572
TS
1117
1118 dirpath = g_strdup_printf("%s/slaves", syspath);
1119 dir = opendir(dirpath);
1120 if (!dir) {
8251a72f
MR
1121 if (errno != ENOENT) {
1122 error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
1123 }
46d4c572
TS
1124 g_free(dirpath);
1125 return;
1126 }
46d4c572
TS
1127
1128 for (;;) {
e668d1b8
HZ
1129 errno = 0;
1130 entry = readdir(dir);
1131 if (entry == NULL) {
1132 if (errno) {
1133 error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
1134 }
46d4c572
TS
1135 break;
1136 }
1137
e668d1b8
HZ
1138 if (entry->d_type == DT_LNK) {
1139 char *path;
1140
1141 g_debug(" slave device '%s'", entry->d_name);
1142 path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
292743d9 1143 build_guest_fsinfo_for_device(path, fs, &err);
e668d1b8 1144 g_free(path);
46d4c572 1145
292743d9
MA
1146 if (err) {
1147 error_propagate(errp, err);
46d4c572
TS
1148 break;
1149 }
1150 }
1151 }
1152
e668d1b8 1153 g_free(dirpath);
46d4c572
TS
1154 closedir(dir);
1155}
1156
fed39564
TG
1157static bool is_disk_virtual(const char *devpath, Error **errp)
1158{
1159 g_autofree char *syspath = realpath(devpath, NULL);
1160
1161 if (!syspath) {
1162 error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
1163 return false;
1164 }
1165 return strstr(syspath, "/devices/virtual/block/") != NULL;
1166}
1167
46d4c572
TS
1168/* Dispatch to functions for virtual/real device */
1169static void build_guest_fsinfo_for_device(char const *devpath,
1170 GuestFilesystemInfo *fs,
1171 Error **errp)
1172{
fed39564
TG
1173 ERRP_GUARD();
1174 g_autofree char *syspath = NULL;
1175 bool is_virtual = false;
46d4c572 1176
fed39564 1177 syspath = realpath(devpath, NULL);
46d4c572
TS
1178 if (!syspath) {
1179 error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
1180 return;
1181 }
1182
1183 if (!fs->name) {
3e015d81 1184 fs->name = g_path_get_basename(syspath);
46d4c572
TS
1185 }
1186
1187 g_debug(" parse sysfs path '%s'", syspath);
fed39564
TG
1188 is_virtual = is_disk_virtual(syspath, errp);
1189 if (*errp != NULL) {
1190 return;
1191 }
1192 if (is_virtual) {
46d4c572
TS
1193 build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
1194 } else {
1195 build_guest_fsinfo_for_real_device(syspath, fs, errp);
1196 }
fed39564
TG
1197}
1198
1199#ifdef CONFIG_LIBUDEV
1200
1201/*
1202 * Wrapper around build_guest_fsinfo_for_device() for getting just
1203 * the disk address.
1204 */
1205static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
1206{
1207 g_autoptr(GuestFilesystemInfo) fs = NULL;
46d4c572 1208
fed39564
TG
1209 fs = g_new0(GuestFilesystemInfo, 1);
1210 build_guest_fsinfo_for_device(syspath, fs, errp);
1211 if (fs->disk != NULL) {
1212 return g_steal_pointer(&fs->disk->value);
1213 }
1214 return NULL;
46d4c572
TS
1215}
1216
fed39564
TG
1217static char *get_alias_for_syspath(const char *syspath)
1218{
1219 struct udev *udev = NULL;
1220 struct udev_device *udevice = NULL;
1221 char *ret = NULL;
1222
1223 udev = udev_new();
1224 if (udev == NULL) {
1225 g_debug("failed to query udev");
1226 goto out;
1227 }
1228 udevice = udev_device_new_from_syspath(udev, syspath);
1229 if (udevice == NULL) {
1230 g_debug("failed to query udev for path: %s", syspath);
1231 goto out;
1232 } else {
1233 const char *alias = udev_device_get_property_value(
1234 udevice, "DM_NAME");
1235 /*
1236 * NULL means there was an error and empty string means there is no
1237 * alias. In case of no alias we return NULL instead of empty string.
1238 */
1239 if (alias == NULL) {
1240 g_debug("failed to query udev for device alias for: %s",
1241 syspath);
1242 } else if (*alias != 0) {
1243 ret = g_strdup(alias);
1244 }
1245 }
1246
1247out:
1248 udev_unref(udev);
1249 udev_device_unref(udevice);
1250 return ret;
1251}
1252
1253static char *get_device_for_syspath(const char *syspath)
1254{
1255 struct udev *udev = NULL;
1256 struct udev_device *udevice = NULL;
1257 char *ret = NULL;
1258
1259 udev = udev_new();
1260 if (udev == NULL) {
1261 g_debug("failed to query udev");
1262 goto out;
1263 }
1264 udevice = udev_device_new_from_syspath(udev, syspath);
1265 if (udevice == NULL) {
1266 g_debug("failed to query udev for path: %s", syspath);
1267 goto out;
1268 } else {
1269 ret = g_strdup(udev_device_get_devnode(udevice));
1270 }
1271
1272out:
1273 udev_unref(udev);
1274 udev_device_unref(udevice);
1275 return ret;
1276}
1277
1278static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
1279{
1280 g_autofree char *deps_dir = NULL;
1281 const gchar *dep;
1282 GDir *dp_deps = NULL;
1283
1284 /* List dependent disks */
1285 deps_dir = g_strdup_printf("%s/slaves", disk_dir);
1286 g_debug(" listing entries in: %s", deps_dir);
1287 dp_deps = g_dir_open(deps_dir, 0, NULL);
1288 if (dp_deps == NULL) {
1289 g_debug("failed to list entries in %s", deps_dir);
1290 return;
1291 }
a8aa94b5 1292 disk->has_dependencies = true;
fed39564
TG
1293 while ((dep = g_dir_read_name(dp_deps)) != NULL) {
1294 g_autofree char *dep_dir = NULL;
fed39564
TG
1295 char *dev_name;
1296
1297 /* Add dependent disks */
1298 dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
1299 dev_name = get_device_for_syspath(dep_dir);
1300 if (dev_name != NULL) {
1301 g_debug(" adding dependent device: %s", dev_name);
54aa3de7 1302 QAPI_LIST_PREPEND(disk->dependencies, dev_name);
fed39564
TG
1303 }
1304 }
1305 g_dir_close(dp_deps);
1306}
1307
1308/*
1309 * Detect partitions subdirectory, name is "<disk_name><number>" or
1310 * "<disk_name>p<number>"
1311 *
1312 * @disk_name -- last component of /sys path (e.g. sda)
1313 * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
1314 * @disk_dev -- device node of the disk (e.g. /dev/sda)
1315 */
1316static GuestDiskInfoList *get_disk_partitions(
1317 GuestDiskInfoList *list,
1318 const char *disk_name, const char *disk_dir,
1319 const char *disk_dev)
1320{
54aa3de7 1321 GuestDiskInfoList *ret = list;
fed39564
TG
1322 struct dirent *de_disk;
1323 DIR *dp_disk = NULL;
1324 size_t len = strlen(disk_name);
1325
1326 dp_disk = opendir(disk_dir);
1327 while ((de_disk = readdir(dp_disk)) != NULL) {
1328 g_autofree char *partition_dir = NULL;
1329 char *dev_name;
1330 GuestDiskInfo *partition;
1331
1332 if (!(de_disk->d_type & DT_DIR)) {
1333 continue;
1334 }
1335
1336 if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
1337 ((*(de_disk->d_name + len) == 'p' &&
1338 isdigit(*(de_disk->d_name + len + 1))) ||
1339 isdigit(*(de_disk->d_name + len))))) {
1340 continue;
1341 }
1342
1343 partition_dir = g_strdup_printf("%s/%s",
1344 disk_dir, de_disk->d_name);
1345 dev_name = get_device_for_syspath(partition_dir);
1346 if (dev_name == NULL) {
1347 g_debug("Failed to get device name for syspath: %s",
1348 disk_dir);
1349 continue;
1350 }
1351 partition = g_new0(GuestDiskInfo, 1);
1352 partition->name = dev_name;
1353 partition->partition = true;
bac9b87b 1354 partition->has_dependencies = true;
fed39564 1355 /* Add parent disk as dependent for easier tracking of hierarchy */
54aa3de7 1356 QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev));
fed39564 1357
54aa3de7 1358 QAPI_LIST_PREPEND(ret, partition);
fed39564
TG
1359 }
1360 closedir(dp_disk);
1361
1362 return ret;
1363}
1364
1365GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
1366{
54aa3de7 1367 GuestDiskInfoList *ret = NULL;
fed39564
TG
1368 GuestDiskInfo *disk;
1369 DIR *dp = NULL;
1370 struct dirent *de = NULL;
1371
1372 g_debug("listing /sys/block directory");
1373 dp = opendir("/sys/block");
1374 if (dp == NULL) {
1375 error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
1376 return NULL;
1377 }
1378 while ((de = readdir(dp)) != NULL) {
1379 g_autofree char *disk_dir = NULL, *line = NULL,
1380 *size_path = NULL;
1381 char *dev_name;
1382 Error *local_err = NULL;
1383 if (de->d_type != DT_LNK) {
1384 g_debug(" skipping entry: %s", de->d_name);
1385 continue;
1386 }
1387
1388 /* Check size and skip zero-sized disks */
1389 g_debug(" checking disk size");
1390 size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
1391 if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
1392 g_debug(" failed to read disk size");
1393 continue;
1394 }
1395 if (g_strcmp0(line, "0\n") == 0) {
1396 g_debug(" skipping zero-sized disk");
1397 continue;
1398 }
1399
1400 g_debug(" adding %s", de->d_name);
1401 disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
1402 dev_name = get_device_for_syspath(disk_dir);
1403 if (dev_name == NULL) {
1404 g_debug("Failed to get device name for syspath: %s",
1405 disk_dir);
1406 continue;
1407 }
1408 disk = g_new0(GuestDiskInfo, 1);
1409 disk->name = dev_name;
1410 disk->partition = false;
1411 disk->alias = get_alias_for_syspath(disk_dir);
1412 disk->has_alias = (disk->alias != NULL);
54aa3de7 1413 QAPI_LIST_PREPEND(ret, disk);
fed39564
TG
1414
1415 /* Get address for non-virtual devices */
1416 bool is_virtual = is_disk_virtual(disk_dir, &local_err);
1417 if (local_err != NULL) {
1418 g_debug(" failed to check disk path, ignoring error: %s",
1419 error_get_pretty(local_err));
1420 error_free(local_err);
1421 local_err = NULL;
1422 /* Don't try to get the address */
1423 is_virtual = true;
1424 }
1425 if (!is_virtual) {
1426 disk->address = get_disk_address(disk_dir, &local_err);
1427 if (local_err != NULL) {
1428 g_debug(" failed to get device info, ignoring error: %s",
1429 error_get_pretty(local_err));
1430 error_free(local_err);
1431 local_err = NULL;
1432 } else if (disk->address != NULL) {
1433 disk->has_address = true;
1434 }
1435 }
1436
1437 get_disk_deps(disk_dir, disk);
1438 ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
1439 }
b1b9ab1c
MR
1440
1441 closedir(dp);
1442
fed39564
TG
1443 return ret;
1444}
1445
1446#else
1447
1448GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
1449{
1450 error_setg(errp, QERR_UNSUPPORTED);
1451 return NULL;
1452}
1453
1454#endif
1455
46d4c572
TS
1456/* Return a list of the disk device(s)' info which @mount lies on */
1457static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
1458 Error **errp)
1459{
1460 GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
25b5ff1a
CH
1461 struct statvfs buf;
1462 unsigned long used, nonroot_total, fr_size;
46d4c572
TS
1463 char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
1464 mount->devmajor, mount->devminor);
1465
1466 fs->mountpoint = g_strdup(mount->dirname);
1467 fs->type = g_strdup(mount->devtype);
1468 build_guest_fsinfo_for_device(devpath, fs, errp);
1469
25b5ff1a
CH
1470 if (statvfs(fs->mountpoint, &buf) == 0) {
1471 fr_size = buf.f_frsize;
1472 used = buf.f_blocks - buf.f_bfree;
1473 nonroot_total = used + buf.f_bavail;
1474 fs->used_bytes = used * fr_size;
1475 fs->total_bytes = nonroot_total * fr_size;
1476
1477 fs->has_total_bytes = true;
1478 fs->has_used_bytes = true;
1479 }
1480
46d4c572 1481 g_free(devpath);
25b5ff1a 1482
46d4c572
TS
1483 return fs;
1484}
1485
1486GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
1487{
1488 FsMountList mounts;
1489 struct FsMount *mount;
54aa3de7 1490 GuestFilesystemInfoList *ret = NULL;
46d4c572
TS
1491 Error *local_err = NULL;
1492
1493 QTAILQ_INIT(&mounts);
1494 build_fs_mount_list(&mounts, &local_err);
1495 if (local_err) {
1496 error_propagate(errp, local_err);
1497 return NULL;
1498 }
1499
1500 QTAILQ_FOREACH(mount, &mounts, next) {
1501 g_debug("Building guest fsinfo for '%s'", mount->dirname);
1502
54aa3de7 1503 QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err));
46d4c572
TS
1504 if (local_err) {
1505 error_propagate(errp, local_err);
1506 qapi_free_GuestFilesystemInfoList(ret);
1507 ret = NULL;
1508 break;
1509 }
1510 }
1511
1512 free_fs_mount_list(&mounts);
1513 return ret;
1514}
1515
1516
ec0f694c
TS
1517typedef enum {
1518 FSFREEZE_HOOK_THAW = 0,
1519 FSFREEZE_HOOK_FREEZE,
1520} FsfreezeHookArg;
1521
13a439ec 1522static const char *fsfreeze_hook_arg_string[] = {
ec0f694c
TS
1523 "thaw",
1524 "freeze",
1525};
1526
77dbc81b 1527static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
ec0f694c
TS
1528{
1529 int status;
1530 pid_t pid;
1531 const char *hook;
1532 const char *arg_str = fsfreeze_hook_arg_string[arg];
1533 Error *local_err = NULL;
1534
1535 hook = ga_fsfreeze_hook(ga_state);
1536 if (!hook) {
1537 return;
1538 }
1539 if (access(hook, X_OK) != 0) {
77dbc81b 1540 error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
ec0f694c
TS
1541 return;
1542 }
1543
1544 slog("executing fsfreeze hook with arg '%s'", arg_str);
1545 pid = fork();
1546 if (pid == 0) {
1547 setsid();
1548 reopen_fd_to_null(0);
1549 reopen_fd_to_null(1);
1550 reopen_fd_to_null(2);
1551
fcc41961 1552 execl(hook, hook, arg_str, NULL);
ec0f694c
TS
1553 _exit(EXIT_FAILURE);
1554 } else if (pid < 0) {
77dbc81b 1555 error_setg_errno(errp, errno, "failed to create child process");
ec0f694c
TS
1556 return;
1557 }
1558
1559 ga_wait_child(pid, &status, &local_err);
84d18f06 1560 if (local_err) {
77dbc81b 1561 error_propagate(errp, local_err);
ec0f694c
TS
1562 return;
1563 }
1564
1565 if (!WIFEXITED(status)) {
77dbc81b 1566 error_setg(errp, "fsfreeze hook has terminated abnormally");
ec0f694c
TS
1567 return;
1568 }
1569
1570 status = WEXITSTATUS(status);
1571 if (status) {
77dbc81b 1572 error_setg(errp, "fsfreeze hook has failed with status %d", status);
ec0f694c
TS
1573 return;
1574 }
1575}
1576
e3d4d252
MR
1577/*
1578 * Return status of freeze/thaw
1579 */
77dbc81b 1580GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
e3d4d252 1581{
f22d85e9
MR
1582 if (ga_is_frozen(ga_state)) {
1583 return GUEST_FSFREEZE_STATUS_FROZEN;
1584 }
1585
1586 return GUEST_FSFREEZE_STATUS_THAWED;
e3d4d252
MR
1587}
1588
e99bce20
TS
1589int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1590{
1591 return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
1592}
1593
e3d4d252
MR
1594/*
1595 * Walk list of mounted file systems in the guest, and freeze the ones which
1596 * are real local file systems.
1597 */
e99bce20
TS
1598int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
1599 strList *mountpoints,
1600 Error **errp)
e3d4d252
MR
1601{
1602 int ret = 0, i = 0;
e99bce20 1603 strList *list;
af02203f
PB
1604 FsMountList mounts;
1605 struct FsMount *mount;
261551d1 1606 Error *local_err = NULL;
e3d4d252 1607 int fd;
e3d4d252
MR
1608
1609 slog("guest-fsfreeze called");
1610
ec0f694c 1611 execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
84d18f06 1612 if (local_err) {
77dbc81b 1613 error_propagate(errp, local_err);
ec0f694c
TS
1614 return -1;
1615 }
1616
9e8aded4 1617 QTAILQ_INIT(&mounts);
261551d1 1618 build_fs_mount_list(&mounts, &local_err);
84d18f06 1619 if (local_err) {
77dbc81b 1620 error_propagate(errp, local_err);
261551d1 1621 return -1;
e3d4d252
MR
1622 }
1623
1624 /* cannot risk guest agent blocking itself on a write in this state */
f22d85e9 1625 ga_set_frozen(ga_state);
e3d4d252 1626
eae3eb3e 1627 QTAILQ_FOREACH_REVERSE(mount, &mounts, next) {
e99bce20
TS
1628 /* To issue fsfreeze in the reverse order of mounts, check if the
1629 * mount is listed in the list here */
1630 if (has_mountpoints) {
1631 for (list = mountpoints; list; list = list->next) {
1632 if (strcmp(list->value, mount->dirname) == 0) {
1633 break;
1634 }
1635 }
1636 if (!list) {
1637 continue;
1638 }
1639 }
1640
448058aa 1641 fd = qemu_open_old(mount->dirname, O_RDONLY);
e3d4d252 1642 if (fd == -1) {
77dbc81b 1643 error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
e3d4d252
MR
1644 goto error;
1645 }
1646
e35916ac
MT
1647 /* we try to cull filesystems we know won't work in advance, but other
1648 * filesystems may not implement fsfreeze for less obvious reasons.
9e8aded4
MR
1649 * these will report EOPNOTSUPP. we simply ignore these when tallying
1650 * the number of frozen filesystems.
ce2eb6c4
PL
1651 * if a filesystem is mounted more than once (aka bind mount) a
1652 * consecutive attempt to freeze an already frozen filesystem will
1653 * return EBUSY.
9e8aded4
MR
1654 *
1655 * any other error means a failure to freeze a filesystem we
1656 * expect to be freezable, so return an error in those cases
1657 * and return system to thawed state.
e3d4d252
MR
1658 */
1659 ret = ioctl(fd, FIFREEZE);
9e8aded4 1660 if (ret == -1) {
ce2eb6c4 1661 if (errno != EOPNOTSUPP && errno != EBUSY) {
77dbc81b 1662 error_setg_errno(errp, errno, "failed to freeze %s",
617fbbc1 1663 mount->dirname);
9e8aded4
MR
1664 close(fd);
1665 goto error;
1666 }
1667 } else {
1668 i++;
e3d4d252
MR
1669 }
1670 close(fd);
e3d4d252
MR
1671 }
1672
af02203f 1673 free_fs_mount_list(&mounts);
65650f01
CH
1674 /* We may not issue any FIFREEZE here.
1675 * Just unset ga_state here and ready for the next call.
1676 */
1677 if (i == 0) {
1678 ga_unset_frozen(ga_state);
1679 }
e3d4d252
MR
1680 return i;
1681
1682error:
af02203f 1683 free_fs_mount_list(&mounts);
9e8aded4 1684 qmp_guest_fsfreeze_thaw(NULL);
e3d4d252
MR
1685 return 0;
1686}
1687
1688/*
1689 * Walk list of frozen file systems in the guest, and thaw them.
1690 */
77dbc81b 1691int64_t qmp_guest_fsfreeze_thaw(Error **errp)
e3d4d252
MR
1692{
1693 int ret;
af02203f
PB
1694 FsMountList mounts;
1695 FsMount *mount;
9e8aded4 1696 int fd, i = 0, logged;
261551d1 1697 Error *local_err = NULL;
9e8aded4
MR
1698
1699 QTAILQ_INIT(&mounts);
261551d1 1700 build_fs_mount_list(&mounts, &local_err);
84d18f06 1701 if (local_err) {
77dbc81b 1702 error_propagate(errp, local_err);
9e8aded4
MR
1703 return 0;
1704 }
e3d4d252 1705
9e8aded4
MR
1706 QTAILQ_FOREACH(mount, &mounts, next) {
1707 logged = false;
448058aa 1708 fd = qemu_open_old(mount->dirname, O_RDONLY);
e3d4d252 1709 if (fd == -1) {
e3d4d252
MR
1710 continue;
1711 }
9e8aded4
MR
1712 /* we have no way of knowing whether a filesystem was actually unfrozen
1713 * as a result of a successful call to FITHAW, only that if an error
1714 * was returned the filesystem was *not* unfrozen by that particular
1715 * call.
1716 *
a31f0531 1717 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
9e8aded4
MR
1718 * to unfreeze, continuing issuing FITHAW until an error is returned,
1719 * in which case either the filesystem is in an unfreezable state, or,
1720 * more likely, it was thawed previously (and remains so afterward).
1721 *
1722 * also, since the most recent successful call is the one that did
1723 * the actual unfreeze, we can use this to provide an accurate count
1724 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
1725 * may * be useful for determining whether a filesystem was unfrozen
1726 * during the freeze/thaw phase by a process other than qemu-ga.
1727 */
1728 do {
1729 ret = ioctl(fd, FITHAW);
1730 if (ret == 0 && !logged) {
1731 i++;
1732 logged = true;
1733 }
1734 } while (ret == 0);
e3d4d252 1735 close(fd);
e3d4d252
MR
1736 }
1737
f22d85e9 1738 ga_unset_frozen(ga_state);
af02203f 1739 free_fs_mount_list(&mounts);
ec0f694c 1740
77dbc81b 1741 execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
ec0f694c 1742
e3d4d252
MR
1743 return i;
1744}
1745
e3d4d252
MR
1746static void guest_fsfreeze_cleanup(void)
1747{
e3d4d252
MR
1748 Error *err = NULL;
1749
f22d85e9 1750 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
6f686749
MA
1751 qmp_guest_fsfreeze_thaw(&err);
1752 if (err) {
1753 slog("failed to clean up frozen filesystems: %s",
1754 error_get_pretty(err));
1755 error_free(err);
e3d4d252
MR
1756 }
1757 }
1758}
e72c3f2e 1759#endif /* CONFIG_FSFREEZE */
e3d4d252 1760
eab5fd59
PB
1761#if defined(CONFIG_FSTRIM)
1762/*
1763 * Walk list of mounted file systems in the guest, and trim them.
1764 */
e82855d9
JO
1765GuestFilesystemTrimResponse *
1766qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
eab5fd59 1767{
e82855d9 1768 GuestFilesystemTrimResponse *response;
e82855d9 1769 GuestFilesystemTrimResult *result;
eab5fd59
PB
1770 int ret = 0;
1771 FsMountList mounts;
1772 struct FsMount *mount;
1773 int fd;
261551d1 1774 Error *local_err = NULL;
73a652a1 1775 struct fstrim_range r;
eab5fd59
PB
1776
1777 slog("guest-fstrim called");
1778
1779 QTAILQ_INIT(&mounts);
261551d1 1780 build_fs_mount_list(&mounts, &local_err);
84d18f06 1781 if (local_err) {
77dbc81b 1782 error_propagate(errp, local_err);
e82855d9 1783 return NULL;
eab5fd59
PB
1784 }
1785
e82855d9
JO
1786 response = g_malloc0(sizeof(*response));
1787
eab5fd59 1788 QTAILQ_FOREACH(mount, &mounts, next) {
e82855d9
JO
1789 result = g_malloc0(sizeof(*result));
1790 result->path = g_strdup(mount->dirname);
1791
54aa3de7 1792 QAPI_LIST_PREPEND(response->paths, result);
e82855d9 1793
448058aa 1794 fd = qemu_open_old(mount->dirname, O_RDONLY);
eab5fd59 1795 if (fd == -1) {
e82855d9
JO
1796 result->error = g_strdup_printf("failed to open: %s",
1797 strerror(errno));
1798 result->has_error = true;
1799 continue;
eab5fd59
PB
1800 }
1801
e35916ac
MT
1802 /* We try to cull filesystems we know won't work in advance, but other
1803 * filesystems may not implement fstrim for less obvious reasons.
1804 * These will report EOPNOTSUPP; while in some other cases ENOTTY
1805 * will be reported (e.g. CD-ROMs).
e82855d9 1806 * Any other error means an unexpected error.
eab5fd59 1807 */
73a652a1
JO
1808 r.start = 0;
1809 r.len = -1;
1810 r.minlen = has_minimum ? minimum : 0;
eab5fd59
PB
1811 ret = ioctl(fd, FITRIM, &r);
1812 if (ret == -1) {
e82855d9
JO
1813 result->has_error = true;
1814 if (errno == ENOTTY || errno == EOPNOTSUPP) {
1815 result->error = g_strdup("trim not supported");
1816 } else {
1817 result->error = g_strdup_printf("failed to trim: %s",
1818 strerror(errno));
eab5fd59 1819 }
e82855d9
JO
1820 close(fd);
1821 continue;
eab5fd59 1822 }
e82855d9
JO
1823
1824 result->has_minimum = true;
1825 result->minimum = r.minlen;
1826 result->has_trimmed = true;
1827 result->trimmed = r.len;
eab5fd59
PB
1828 close(fd);
1829 }
1830
eab5fd59 1831 free_fs_mount_list(&mounts);
e82855d9 1832 return response;
eab5fd59
PB
1833}
1834#endif /* CONFIG_FSTRIM */
1835
1836
11d0f125
LC
1837#define LINUX_SYS_STATE_FILE "/sys/power/state"
1838#define SUSPEND_SUPPORTED 0
1839#define SUSPEND_NOT_SUPPORTED 1
1840
8b020b5e
DHB
1841typedef enum {
1842 SUSPEND_MODE_DISK = 0,
1843 SUSPEND_MODE_RAM = 1,
1844 SUSPEND_MODE_HYBRID = 2,
1845} SuspendMode;
1846
1847/*
1848 * Executes a command in a child process using g_spawn_sync,
1849 * returning an int >= 0 representing the exit status of the
1850 * process.
1851 *
1852 * If the program wasn't found in path, returns -1.
1853 *
1854 * If a problem happened when creating the child process,
1855 * returns -1 and errp is set.
1856 */
1857static int run_process_child(const char *command[], Error **errp)
11d0f125 1858{
8b020b5e
DHB
1859 int exit_status, spawn_flag;
1860 GError *g_err = NULL;
1861 bool success;
1862
1863 spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
1864 G_SPAWN_STDERR_TO_DEV_NULL;
11d0f125 1865
fcc41961 1866 success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
8b020b5e
DHB
1867 NULL, NULL, NULL, NULL,
1868 &exit_status, &g_err);
304a0fcb 1869
8b020b5e
DHB
1870 if (success) {
1871 return WEXITSTATUS(exit_status);
304a0fcb
DHB
1872 }
1873
8b020b5e
DHB
1874 if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
1875 error_setg(errp, "failed to create child process, error '%s'",
1876 g_err->message);
a5fcf0e3 1877 }
11d0f125 1878
8b020b5e
DHB
1879 g_error_free(g_err);
1880 return -1;
1881}
1882
067927d6
DHB
1883static bool systemd_supports_mode(SuspendMode mode, Error **errp)
1884{
067927d6
DHB
1885 const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
1886 "systemd-hybrid-sleep"};
1887 const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
1888 int status;
1889
992861fb 1890 status = run_process_child(cmd, errp);
067927d6
DHB
1891
1892 /*
1893 * systemctl status uses LSB return codes so we can expect
1894 * status > 0 and be ok. To assert if the guest has support
1895 * for the selected suspend mode, status should be < 4. 4 is
1896 * the code for unknown service status, the return value when
1897 * the service does not exist. A common value is status = 3
1898 * (program is not running).
1899 */
1900 if (status > 0 && status < 4) {
1901 return true;
1902 }
1903
067927d6
DHB
1904 return false;
1905}
1906
1907static void systemd_suspend(SuspendMode mode, Error **errp)
1908{
1909 Error *local_err = NULL;
1910 const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
1911 const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
1912 int status;
1913
1914 status = run_process_child(cmd, &local_err);
1915
1916 if (status == 0) {
1917 return;
1918 }
1919
1920 if ((status == -1) && !local_err) {
1921 error_setg(errp, "the helper program 'systemctl %s' was not found",
1922 systemctl_args[mode]);
1923 return;
1924 }
1925
1926 if (local_err) {
1927 error_propagate(errp, local_err);
1928 } else {
1929 error_setg(errp, "the helper program 'systemctl %s' returned an "
1930 "unexpected exit status code (%d)",
1931 systemctl_args[mode], status);
1932 }
1933}
1934
8b020b5e
DHB
1935static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
1936{
1937 Error *local_err = NULL;
1938 const char *pmutils_args[3] = {"--hibernate", "--suspend",
1939 "--suspend-hybrid"};
1940 const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
1941 int status;
1942
1943 status = run_process_child(cmd, &local_err);
1944
1945 if (status == SUSPEND_SUPPORTED) {
1946 return true;
11d0f125
LC
1947 }
1948
8b020b5e
DHB
1949 if ((status == -1) && !local_err) {
1950 return false;
6b26e837 1951 }
11d0f125 1952
8b020b5e
DHB
1953 if (local_err) {
1954 error_propagate(errp, local_err);
1955 } else {
77dbc81b 1956 error_setg(errp,
8b020b5e
DHB
1957 "the helper program '%s' returned an unexpected exit"
1958 " status code (%d)", "pm-is-supported", status);
11d0f125
LC
1959 }
1960
8b020b5e 1961 return false;
a5fcf0e3
DHB
1962}
1963
8b020b5e 1964static void pmutils_suspend(SuspendMode mode, Error **errp)
246d76eb
DHB
1965{
1966 Error *local_err = NULL;
8b020b5e
DHB
1967 const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
1968 "pm-suspend-hybrid"};
1969 const char *cmd[2] = {pmutils_binaries[mode], NULL};
246d76eb
DHB
1970 int status;
1971
8b020b5e 1972 status = run_process_child(cmd, &local_err);
246d76eb 1973
8b020b5e 1974 if (status == 0) {
246d76eb
DHB
1975 return;
1976 }
1977
8b020b5e
DHB
1978 if ((status == -1) && !local_err) {
1979 error_setg(errp, "the helper program '%s' was not found",
1980 pmutils_binaries[mode]);
1981 return;
246d76eb
DHB
1982 }
1983
246d76eb
DHB
1984 if (local_err) {
1985 error_propagate(errp, local_err);
8b020b5e 1986 } else {
246d76eb 1987 error_setg(errp,
8b020b5e
DHB
1988 "the helper program '%s' returned an unexpected exit"
1989 " status code (%d)", pmutils_binaries[mode], status);
246d76eb 1990 }
246d76eb
DHB
1991}
1992
8b020b5e 1993static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
a5fcf0e3 1994{
8b020b5e
DHB
1995 const char *sysfile_strs[3] = {"disk", "mem", NULL};
1996 const char *sysfile_str = sysfile_strs[mode];
a5fcf0e3
DHB
1997 char buf[32]; /* hopefully big enough */
1998 int fd;
1999 ssize_t ret;
2000
8b020b5e
DHB
2001 if (!sysfile_str) {
2002 error_setg(errp, "unknown guest suspend mode");
a5fcf0e3
DHB
2003 return false;
2004 }
2005
2006 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
2007 if (fd < 0) {
2008 return false;
2009 }
2010
2011 ret = read(fd, buf, sizeof(buf) - 1);
d9c745c1 2012 close(fd);
a5fcf0e3
DHB
2013 if (ret <= 0) {
2014 return false;
2015 }
2016 buf[ret] = '\0';
2017
2018 if (strstr(buf, sysfile_str)) {
2019 return true;
2020 }
2021 return false;
2022}
2023
8b020b5e 2024static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
11d0f125 2025{
7b376087 2026 Error *local_err = NULL;
8b020b5e
DHB
2027 const char *sysfile_strs[3] = {"disk", "mem", NULL};
2028 const char *sysfile_str = sysfile_strs[mode];
7b376087 2029 pid_t pid;
dc8764f0 2030 int status;
11d0f125 2031
8b020b5e 2032 if (!sysfile_str) {
304a0fcb
DHB
2033 error_setg(errp, "unknown guest suspend mode");
2034 return;
2035 }
2036
11d0f125 2037 pid = fork();
246d76eb 2038 if (!pid) {
11d0f125
LC
2039 /* child */
2040 int fd;
2041
2042 setsid();
2043 reopen_fd_to_null(0);
2044 reopen_fd_to_null(1);
2045 reopen_fd_to_null(2);
2046
11d0f125
LC
2047 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
2048 if (fd < 0) {
2049 _exit(EXIT_FAILURE);
2050 }
2051
2052 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
2053 _exit(EXIT_FAILURE);
2054 }
2055
2056 _exit(EXIT_SUCCESS);
7b376087 2057 } else if (pid < 0) {
77dbc81b 2058 error_setg_errno(errp, errno, "failed to create child process");
246d76eb 2059 return;
11d0f125
LC
2060 }
2061
7b376087 2062 ga_wait_child(pid, &status, &local_err);
84d18f06 2063 if (local_err) {
77dbc81b 2064 error_propagate(errp, local_err);
246d76eb 2065 return;
dc8764f0
LC
2066 }
2067
7b376087 2068 if (WEXITSTATUS(status)) {
77dbc81b 2069 error_setg(errp, "child process has failed to suspend");
11d0f125 2070 }
dc8764f0 2071
246d76eb
DHB
2072}
2073
8b020b5e 2074static void guest_suspend(SuspendMode mode, Error **errp)
246d76eb
DHB
2075{
2076 Error *local_err = NULL;
73e1d8eb 2077 bool mode_supported = false;
246d76eb 2078
73e1d8eb
DHB
2079 if (systemd_supports_mode(mode, &local_err)) {
2080 mode_supported = true;
2081 systemd_suspend(mode, &local_err);
246d76eb
DHB
2082 }
2083
067927d6
DHB
2084 if (!local_err) {
2085 return;
2086 }
2087
2088 error_free(local_err);
6a4a3853 2089 local_err = NULL;
067927d6 2090
73e1d8eb
DHB
2091 if (pmutils_supports_mode(mode, &local_err)) {
2092 mode_supported = true;
2093 pmutils_suspend(mode, &local_err);
2094 }
2095
246d76eb
DHB
2096 if (!local_err) {
2097 return;
2098 }
2099
2100 error_free(local_err);
6a4a3853 2101 local_err = NULL;
246d76eb 2102
73e1d8eb
DHB
2103 if (linux_sys_state_supports_mode(mode, &local_err)) {
2104 mode_supported = true;
2105 linux_sys_state_suspend(mode, &local_err);
2106 }
2107
2108 if (!mode_supported) {
6a4a3853 2109 error_free(local_err);
73e1d8eb
DHB
2110 error_setg(errp,
2111 "the requested suspend mode is not supported by the guest");
b2322003 2112 } else {
246d76eb
DHB
2113 error_propagate(errp, local_err);
2114 }
11d0f125
LC
2115}
2116
77dbc81b 2117void qmp_guest_suspend_disk(Error **errp)
11d0f125 2118{
304a0fcb 2119 guest_suspend(SUSPEND_MODE_DISK, errp);
11d0f125
LC
2120}
2121
77dbc81b 2122void qmp_guest_suspend_ram(Error **errp)
fbf42210 2123{
304a0fcb 2124 guest_suspend(SUSPEND_MODE_RAM, errp);
fbf42210
LC
2125}
2126
77dbc81b 2127void qmp_guest_suspend_hybrid(Error **errp)
95f4f404 2128{
304a0fcb 2129 guest_suspend(SUSPEND_MODE_HYBRID, errp);
95f4f404
LC
2130}
2131
96291f13 2132static GuestNetworkInterface *
3424fc9f
MP
2133guest_find_interface(GuestNetworkInterfaceList *head,
2134 const char *name)
2135{
2136 for (; head; head = head->next) {
2137 if (strcmp(head->value->name, name) == 0) {
96291f13 2138 return head->value;
3424fc9f
MP
2139 }
2140 }
2141
96291f13 2142 return NULL;
3424fc9f
MP
2143}
2144
53f9fcb2
ZL
2145static int guest_get_network_stats(const char *name,
2146 GuestNetworkInterfaceStat *stats)
2147{
2148 int name_len;
2149 char const *devinfo = "/proc/net/dev";
2150 FILE *fp;
2151 char *line = NULL, *colon;
2152 size_t n = 0;
2153 fp = fopen(devinfo, "r");
2154 if (!fp) {
2155 return -1;
2156 }
2157 name_len = strlen(name);
2158 while (getline(&line, &n, fp) != -1) {
2159 long long dummy;
2160 long long rx_bytes;
2161 long long rx_packets;
2162 long long rx_errs;
2163 long long rx_dropped;
2164 long long tx_bytes;
2165 long long tx_packets;
2166 long long tx_errs;
2167 long long tx_dropped;
2168 char *trim_line;
2169 trim_line = g_strchug(line);
2170 if (trim_line[0] == '\0') {
2171 continue;
2172 }
2173 colon = strchr(trim_line, ':');
2174 if (!colon) {
2175 continue;
2176 }
2177 if (colon - name_len == trim_line &&
2178 strncmp(trim_line, name, name_len) == 0) {
2179 if (sscanf(colon + 1,
2180 "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
2181 &rx_bytes, &rx_packets, &rx_errs, &rx_dropped,
2182 &dummy, &dummy, &dummy, &dummy,
2183 &tx_bytes, &tx_packets, &tx_errs, &tx_dropped,
2184 &dummy, &dummy, &dummy, &dummy) != 16) {
2185 continue;
2186 }
2187 stats->rx_bytes = rx_bytes;
2188 stats->rx_packets = rx_packets;
2189 stats->rx_errs = rx_errs;
2190 stats->rx_dropped = rx_dropped;
2191 stats->tx_bytes = tx_bytes;
2192 stats->tx_packets = tx_packets;
2193 stats->tx_errs = tx_errs;
2194 stats->tx_dropped = tx_dropped;
2195 fclose(fp);
2196 g_free(line);
2197 return 0;
2198 }
2199 }
2200 fclose(fp);
2201 g_free(line);
2202 g_debug("/proc/net/dev: Interface '%s' not found", name);
2203 return -1;
2204}
2205
3424fc9f
MP
2206/*
2207 * Build information about guest interfaces
2208 */
2209GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
2210{
96291f13 2211 GuestNetworkInterfaceList *head = NULL, **tail = &head;
3424fc9f 2212 struct ifaddrs *ifap, *ifa;
3424fc9f
MP
2213
2214 if (getifaddrs(&ifap) < 0) {
878a0ae0 2215 error_setg_errno(errp, errno, "getifaddrs failed");
3424fc9f
MP
2216 goto error;
2217 }
2218
2219 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
96291f13
EB
2220 GuestNetworkInterface *info;
2221 GuestIpAddressList **address_tail;
2222 GuestIpAddress *address_item = NULL;
2223 GuestNetworkInterfaceStat *interface_stat = NULL;
3424fc9f
MP
2224 char addr4[INET_ADDRSTRLEN];
2225 char addr6[INET6_ADDRSTRLEN];
2226 int sock;
2227 struct ifreq ifr;
2228 unsigned char *mac_addr;
2229 void *p;
2230
2231 g_debug("Processing %s interface", ifa->ifa_name);
2232
2233 info = guest_find_interface(head, ifa->ifa_name);
2234
2235 if (!info) {
2236 info = g_malloc0(sizeof(*info));
96291f13 2237 info->name = g_strdup(ifa->ifa_name);
3424fc9f 2238
96291f13 2239 QAPI_LIST_APPEND(tail, info);
3424fc9f
MP
2240 }
2241
96291f13 2242 if (!info->has_hardware_address && ifa->ifa_flags & SIOCGIFHWADDR) {
3424fc9f
MP
2243 /* we haven't obtained HW address yet */
2244 sock = socket(PF_INET, SOCK_STREAM, 0);
2245 if (sock == -1) {
878a0ae0 2246 error_setg_errno(errp, errno, "failed to create socket");
3424fc9f
MP
2247 goto error;
2248 }
2249
2250 memset(&ifr, 0, sizeof(ifr));
96291f13 2251 pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->name);
3424fc9f 2252 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
878a0ae0
LC
2253 error_setg_errno(errp, errno,
2254 "failed to get MAC address of %s",
2255 ifa->ifa_name);
10a2158f 2256 close(sock);
3424fc9f
MP
2257 goto error;
2258 }
2259
10a2158f 2260 close(sock);
3424fc9f
MP
2261 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
2262
96291f13 2263 info->hardware_address =
e4ada482
SW
2264 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
2265 (int) mac_addr[0], (int) mac_addr[1],
2266 (int) mac_addr[2], (int) mac_addr[3],
2267 (int) mac_addr[4], (int) mac_addr[5]);
3424fc9f 2268
96291f13 2269 info->has_hardware_address = true;
3424fc9f
MP
2270 }
2271
2272 if (ifa->ifa_addr &&
2273 ifa->ifa_addr->sa_family == AF_INET) {
2274 /* interface with IPv4 address */
3424fc9f
MP
2275 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
2276 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
878a0ae0 2277 error_setg_errno(errp, errno, "inet_ntop failed");
3424fc9f
MP
2278 goto error;
2279 }
2280
10a2158f 2281 address_item = g_malloc0(sizeof(*address_item));
96291f13
EB
2282 address_item->ip_address = g_strdup(addr4);
2283 address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
3424fc9f
MP
2284
2285 if (ifa->ifa_netmask) {
2286 /* Count the number of set bits in netmask.
2287 * This is safe as '1' and '0' cannot be shuffled in netmask. */
2288 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
96291f13 2289 address_item->prefix = ctpop32(((uint32_t *) p)[0]);
3424fc9f
MP
2290 }
2291 } else if (ifa->ifa_addr &&
2292 ifa->ifa_addr->sa_family == AF_INET6) {
2293 /* interface with IPv6 address */
3424fc9f
MP
2294 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
2295 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
878a0ae0 2296 error_setg_errno(errp, errno, "inet_ntop failed");
3424fc9f
MP
2297 goto error;
2298 }
2299
10a2158f 2300 address_item = g_malloc0(sizeof(*address_item));
96291f13
EB
2301 address_item->ip_address = g_strdup(addr6);
2302 address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
3424fc9f
MP
2303
2304 if (ifa->ifa_netmask) {
2305 /* Count the number of set bits in netmask.
2306 * This is safe as '1' and '0' cannot be shuffled in netmask. */
2307 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
96291f13 2308 address_item->prefix =
3424fc9f
MP
2309 ctpop32(((uint32_t *) p)[0]) +
2310 ctpop32(((uint32_t *) p)[1]) +
2311 ctpop32(((uint32_t *) p)[2]) +
2312 ctpop32(((uint32_t *) p)[3]);
2313 }
2314 }
2315
2316 if (!address_item) {
2317 continue;
2318 }
2319
96291f13
EB
2320 address_tail = &info->ip_addresses;
2321 while (*address_tail) {
2322 address_tail = &(*address_tail)->next;
3424fc9f 2323 }
96291f13 2324 QAPI_LIST_APPEND(address_tail, address_item);
3424fc9f 2325
96291f13 2326 info->has_ip_addresses = true;
3424fc9f 2327
96291f13 2328 if (!info->has_statistics) {
53f9fcb2 2329 interface_stat = g_malloc0(sizeof(*interface_stat));
96291f13
EB
2330 if (guest_get_network_stats(info->name, interface_stat) == -1) {
2331 info->has_statistics = false;
53f9fcb2
ZL
2332 g_free(interface_stat);
2333 } else {
96291f13
EB
2334 info->statistics = interface_stat;
2335 info->has_statistics = true;
53f9fcb2
ZL
2336 }
2337 }
3424fc9f
MP
2338 }
2339
2340 freeifaddrs(ifap);
2341 return head;
2342
2343error:
2344 freeifaddrs(ifap);
2345 qapi_free_GuestNetworkInterfaceList(head);
2346 return NULL;
2347}
2348
d2baff62
LE
2349/* Transfer online/offline status between @vcpu and the guest system.
2350 *
2351 * On input either @errp or *@errp must be NULL.
2352 *
2353 * In system-to-@vcpu direction, the following @vcpu fields are accessed:
2354 * - R: vcpu->logical_id
2355 * - W: vcpu->online
2356 * - W: vcpu->can_offline
2357 *
2358 * In @vcpu-to-system direction, the following @vcpu fields are accessed:
2359 * - R: vcpu->logical_id
2360 * - R: vcpu->online
2361 *
2362 * Written members remain unmodified on error.
2363 */
2364static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
b4bf912a 2365 char *dirpath, Error **errp)
d2baff62 2366{
b4bf912a
IM
2367 int fd;
2368 int res;
d2baff62 2369 int dirfd;
b4bf912a 2370 static const char fn[] = "online";
d2baff62 2371
d2baff62
LE
2372 dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2373 if (dirfd == -1) {
2374 error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
b4bf912a
IM
2375 return;
2376 }
d2baff62 2377
b4bf912a
IM
2378 fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
2379 if (fd == -1) {
2380 if (errno != ENOENT) {
2381 error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
2382 } else if (sys2vcpu) {
2383 vcpu->online = true;
2384 vcpu->can_offline = false;
2385 } else if (!vcpu->online) {
2386 error_setg(errp, "logical processor #%" PRId64 " can't be "
2387 "offlined", vcpu->logical_id);
2388 } /* otherwise pretend successful re-onlining */
2389 } else {
2390 unsigned char status;
2391
2392 res = pread(fd, &status, 1, 0);
2393 if (res == -1) {
2394 error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
2395 } else if (res == 0) {
2396 error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
2397 fn);
2398 } else if (sys2vcpu) {
2399 vcpu->online = (status != '0');
2400 vcpu->can_offline = true;
2401 } else if (vcpu->online != (status != '0')) {
2402 status = '0' + vcpu->online;
2403 if (pwrite(fd, &status, 1, 0) == -1) {
2404 error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
2405 fn);
2406 }
2407 } /* otherwise pretend successful re-(on|off)-lining */
d2baff62 2408
b4bf912a 2409 res = close(fd);
d2baff62
LE
2410 g_assert(res == 0);
2411 }
2412
b4bf912a
IM
2413 res = close(dirfd);
2414 g_assert(res == 0);
d2baff62
LE
2415}
2416
2417GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
2418{
c3033fd3 2419 GuestLogicalProcessorList *head, **tail;
27e7de3c
LM
2420 const char *cpu_dir = "/sys/devices/system/cpu";
2421 const gchar *line;
2422 g_autoptr(GDir) cpu_gdir = NULL;
d2baff62
LE
2423 Error *local_err = NULL;
2424
d2baff62 2425 head = NULL;
c3033fd3 2426 tail = &head;
27e7de3c 2427 cpu_gdir = g_dir_open(cpu_dir, 0, NULL);
d2baff62 2428
27e7de3c
LM
2429 if (cpu_gdir == NULL) {
2430 error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir);
2431 return NULL;
2432 }
b4bf912a 2433
27e7de3c
LM
2434 while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) {
2435 GuestLogicalProcessor *vcpu;
2436 int64_t id;
2437 if (sscanf(line, "cpu%" PRId64, &id)) {
2438 g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/"
2439 "cpu%" PRId64 "/", id);
b4bf912a
IM
2440 vcpu = g_malloc0(sizeof *vcpu);
2441 vcpu->logical_id = id;
2442 vcpu->has_can_offline = true; /* lolspeak ftw */
2443 transfer_vcpu(vcpu, true, path, &local_err);
c3033fd3 2444 QAPI_LIST_APPEND(tail, vcpu);
b4bf912a 2445 }
d2baff62
LE
2446 }
2447
2448 if (local_err == NULL) {
2449 /* there's no guest with zero VCPUs */
2450 g_assert(head != NULL);
2451 return head;
2452 }
2453
2454 qapi_free_GuestLogicalProcessorList(head);
2455 error_propagate(errp, local_err);
2456 return NULL;
2457}
2458
cbb65fc2
LE
2459int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
2460{
2461 int64_t processed;
2462 Error *local_err = NULL;
2463
2464 processed = 0;
2465 while (vcpus != NULL) {
b4bf912a
IM
2466 char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
2467 vcpus->value->logical_id);
2468
2469 transfer_vcpu(vcpus->value, false, path, &local_err);
2470 g_free(path);
cbb65fc2
LE
2471 if (local_err != NULL) {
2472 break;
2473 }
2474 ++processed;
2475 vcpus = vcpus->next;
2476 }
2477
2478 if (local_err != NULL) {
2479 if (processed == 0) {
2480 error_propagate(errp, local_err);
2481 } else {
2482 error_free(local_err);
2483 }
2484 }
2485
2486 return processed;
2487}
2488
215a2771
DB
2489void qmp_guest_set_user_password(const char *username,
2490 const char *password,
2491 bool crypted,
2492 Error **errp)
2493{
2494 Error *local_err = NULL;
2495 char *passwd_path = NULL;
2496 pid_t pid;
2497 int status;
2498 int datafd[2] = { -1, -1 };
2499 char *rawpasswddata = NULL;
2500 size_t rawpasswdlen;
2501 char *chpasswddata = NULL;
2502 size_t chpasswdlen;
2503
920639ca
DB
2504 rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
2505 if (!rawpasswddata) {
2506 return;
2507 }
215a2771
DB
2508 rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
2509 rawpasswddata[rawpasswdlen] = '\0';
2510
2511 if (strchr(rawpasswddata, '\n')) {
2512 error_setg(errp, "forbidden characters in raw password");
2513 goto out;
2514 }
2515
2516 if (strchr(username, '\n') ||
2517 strchr(username, ':')) {
2518 error_setg(errp, "forbidden characters in username");
2519 goto out;
2520 }
2521
2522 chpasswddata = g_strdup_printf("%s:%s\n", username, rawpasswddata);
2523 chpasswdlen = strlen(chpasswddata);
2524
2525 passwd_path = g_find_program_in_path("chpasswd");
2526
2527 if (!passwd_path) {
2528 error_setg(errp, "cannot find 'passwd' program in PATH");
2529 goto out;
2530 }
2531
2532 if (pipe(datafd) < 0) {
2533 error_setg(errp, "cannot create pipe FDs");
2534 goto out;
2535 }
2536
2537 pid = fork();
2538 if (pid == 0) {
2539 close(datafd[1]);
2540 /* child */
2541 setsid();
2542 dup2(datafd[0], 0);
2543 reopen_fd_to_null(1);
2544 reopen_fd_to_null(2);
2545
2546 if (crypted) {
fcc41961 2547 execl(passwd_path, "chpasswd", "-e", NULL);
215a2771 2548 } else {
fcc41961 2549 execl(passwd_path, "chpasswd", NULL);
215a2771
DB
2550 }
2551 _exit(EXIT_FAILURE);
2552 } else if (pid < 0) {
2553 error_setg_errno(errp, errno, "failed to create child process");
2554 goto out;
2555 }
2556 close(datafd[0]);
2557 datafd[0] = -1;
2558
2559 if (qemu_write_full(datafd[1], chpasswddata, chpasswdlen) != chpasswdlen) {
2560 error_setg_errno(errp, errno, "cannot write new account password");
2561 goto out;
2562 }
2563 close(datafd[1]);
2564 datafd[1] = -1;
2565
2566 ga_wait_child(pid, &status, &local_err);
2567 if (local_err) {
2568 error_propagate(errp, local_err);
2569 goto out;
2570 }
2571
2572 if (!WIFEXITED(status)) {
2573 error_setg(errp, "child process has terminated abnormally");
2574 goto out;
2575 }
2576
2577 if (WEXITSTATUS(status)) {
2578 error_setg(errp, "child process has failed to set user password");
2579 goto out;
2580 }
2581
2582out:
2583 g_free(chpasswddata);
2584 g_free(rawpasswddata);
2585 g_free(passwd_path);
2586 if (datafd[0] != -1) {
2587 close(datafd[0]);
2588 }
2589 if (datafd[1] != -1) {
2590 close(datafd[1]);
2591 }
2592}
2593
bd240fca
HZ
2594static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
2595 int size, Error **errp)
2596{
2597 int fd;
2598 int res;
2599
2600 errno = 0;
2601 fd = openat(dirfd, pathname, O_RDONLY);
2602 if (fd == -1) {
2603 error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2604 return;
2605 }
2606
2607 res = pread(fd, buf, size, 0);
2608 if (res == -1) {
2609 error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
2610 } else if (res == 0) {
2611 error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
2612 }
2613 close(fd);
2614}
2615
2616static void ga_write_sysfs_file(int dirfd, const char *pathname,
2617 const char *buf, int size, Error **errp)
2618{
2619 int fd;
2620
2621 errno = 0;
2622 fd = openat(dirfd, pathname, O_WRONLY);
2623 if (fd == -1) {
2624 error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2625 return;
2626 }
2627
2628 if (pwrite(fd, buf, size, 0) == -1) {
2629 error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
2630 }
2631
2632 close(fd);
2633}
2634
2635/* Transfer online/offline status between @mem_blk and the guest system.
2636 *
2637 * On input either @errp or *@errp must be NULL.
2638 *
2639 * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
2640 * - R: mem_blk->phys_index
2641 * - W: mem_blk->online
2642 * - W: mem_blk->can_offline
2643 *
2644 * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
2645 * - R: mem_blk->phys_index
2646 * - R: mem_blk->online
2647 *- R: mem_blk->can_offline
2648 * Written members remain unmodified on error.
2649 */
2650static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
2651 GuestMemoryBlockResponse *result,
2652 Error **errp)
2653{
2654 char *dirpath;
2655 int dirfd;
2656 char *status;
2657 Error *local_err = NULL;
2658
2659 if (!sys2memblk) {
2660 DIR *dp;
2661
2662 if (!result) {
2663 error_setg(errp, "Internal error, 'result' should not be NULL");
2664 return;
2665 }
2666 errno = 0;
2667 dp = opendir("/sys/devices/system/memory/");
2668 /* if there is no 'memory' directory in sysfs,
2669 * we think this VM does not support online/offline memory block,
2670 * any other solution?
2671 */
9879f5ac
PMD
2672 if (!dp) {
2673 if (errno == ENOENT) {
2674 result->response =
2675 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2676 }
bd240fca
HZ
2677 goto out1;
2678 }
2679 closedir(dp);
2680 }
2681
2682 dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
2683 mem_blk->phys_index);
2684 dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2685 if (dirfd == -1) {
2686 if (sys2memblk) {
2687 error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2688 } else {
2689 if (errno == ENOENT) {
2690 result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
2691 } else {
2692 result->response =
2693 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2694 }
2695 }
2696 g_free(dirpath);
2697 goto out1;
2698 }
2699 g_free(dirpath);
2700
2701 status = g_malloc0(10);
2702 ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
2703 if (local_err) {
2704 /* treat with sysfs file that not exist in old kernel */
2705 if (errno == ENOENT) {
2706 error_free(local_err);
2707 if (sys2memblk) {
2708 mem_blk->online = true;
2709 mem_blk->can_offline = false;
2710 } else if (!mem_blk->online) {
2711 result->response =
2712 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2713 }
2714 } else {
2715 if (sys2memblk) {
2716 error_propagate(errp, local_err);
2717 } else {
b368123d 2718 error_free(local_err);
bd240fca
HZ
2719 result->response =
2720 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2721 }
2722 }
2723 goto out2;
2724 }
2725
2726 if (sys2memblk) {
2727 char removable = '0';
2728
2729 mem_blk->online = (strncmp(status, "online", 6) == 0);
2730
2731 ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
2732 if (local_err) {
67cc32eb 2733 /* if no 'removable' file, it doesn't support offline mem blk */
bd240fca
HZ
2734 if (errno == ENOENT) {
2735 error_free(local_err);
2736 mem_blk->can_offline = false;
2737 } else {
2738 error_propagate(errp, local_err);
2739 }
2740 } else {
2741 mem_blk->can_offline = (removable != '0');
2742 }
2743 } else {
2744 if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
7064024d 2745 const char *new_state = mem_blk->online ? "online" : "offline";
bd240fca
HZ
2746
2747 ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
2748 &local_err);
bd240fca
HZ
2749 if (local_err) {
2750 error_free(local_err);
2751 result->response =
2752 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2753 goto out2;
2754 }
2755
2756 result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
2757 result->has_error_code = false;
2758 } /* otherwise pretend successful re-(on|off)-lining */
2759 }
2760 g_free(status);
2761 close(dirfd);
2762 return;
2763
2764out2:
2765 g_free(status);
2766 close(dirfd);
2767out1:
2768 if (!sys2memblk) {
2769 result->has_error_code = true;
2770 result->error_code = errno;
2771 }
2772}
2773
a065aaa9
HZ
2774GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2775{
c3033fd3 2776 GuestMemoryBlockList *head, **tail;
bd240fca
HZ
2777 Error *local_err = NULL;
2778 struct dirent *de;
2779 DIR *dp;
2780
2781 head = NULL;
c3033fd3 2782 tail = &head;
bd240fca
HZ
2783
2784 dp = opendir("/sys/devices/system/memory/");
2785 if (!dp) {
f693fe6e
MR
2786 /* it's ok if this happens to be a system that doesn't expose
2787 * memory blocks via sysfs, but otherwise we should report
2788 * an error
2789 */
2790 if (errno != ENOENT) {
2791 error_setg_errno(errp, errno, "Can't open directory"
9af9e0fe 2792 "\"/sys/devices/system/memory/\"");
f693fe6e 2793 }
bd240fca
HZ
2794 return NULL;
2795 }
2796
2797 /* Note: the phys_index of memory block may be discontinuous,
2798 * this is because a memblk is the unit of the Sparse Memory design, which
2799 * allows discontinuous memory ranges (ex. NUMA), so here we should
2800 * traverse the memory block directory.
2801 */
2802 while ((de = readdir(dp)) != NULL) {
2803 GuestMemoryBlock *mem_blk;
bd240fca
HZ
2804
2805 if ((strncmp(de->d_name, "memory", 6) != 0) ||
2806 !(de->d_type & DT_DIR)) {
2807 continue;
2808 }
2809
2810 mem_blk = g_malloc0(sizeof *mem_blk);
2811 /* The d_name is "memoryXXX", phys_index is block id, same as XXX */
2812 mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
2813 mem_blk->has_can_offline = true; /* lolspeak ftw */
2814 transfer_memory_block(mem_blk, true, NULL, &local_err);
4155c998
MA
2815 if (local_err) {
2816 break;
2817 }
bd240fca 2818
c3033fd3 2819 QAPI_LIST_APPEND(tail, mem_blk);
bd240fca
HZ
2820 }
2821
2822 closedir(dp);
2823 if (local_err == NULL) {
2824 /* there's no guest with zero memory blocks */
2825 if (head == NULL) {
2826 error_setg(errp, "guest reported zero memory blocks!");
2827 }
2828 return head;
2829 }
2830
2831 qapi_free_GuestMemoryBlockList(head);
2832 error_propagate(errp, local_err);
a065aaa9
HZ
2833 return NULL;
2834}
2835
2836GuestMemoryBlockResponseList *
2837qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2838{
c3033fd3 2839 GuestMemoryBlockResponseList *head, **tail;
32ca7927
HZ
2840 Error *local_err = NULL;
2841
2842 head = NULL;
c3033fd3 2843 tail = &head;
32ca7927
HZ
2844
2845 while (mem_blks != NULL) {
2846 GuestMemoryBlockResponse *result;
32ca7927
HZ
2847 GuestMemoryBlock *current_mem_blk = mem_blks->value;
2848
2849 result = g_malloc0(sizeof(*result));
2850 result->phys_index = current_mem_blk->phys_index;
2851 transfer_memory_block(current_mem_blk, false, result, &local_err);
2852 if (local_err) { /* should never happen */
2853 goto err;
2854 }
32ca7927 2855
c3033fd3 2856 QAPI_LIST_APPEND(tail, result);
32ca7927
HZ
2857 mem_blks = mem_blks->next;
2858 }
2859
2860 return head;
2861err:
2862 qapi_free_GuestMemoryBlockResponseList(head);
2863 error_propagate(errp, local_err);
a065aaa9
HZ
2864 return NULL;
2865}
2866
2867GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2868{
ef82b60b
HZ
2869 Error *local_err = NULL;
2870 char *dirpath;
2871 int dirfd;
2872 char *buf;
2873 GuestMemoryBlockInfo *info;
2874
2875 dirpath = g_strdup_printf("/sys/devices/system/memory/");
2876 dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2877 if (dirfd == -1) {
2878 error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2879 g_free(dirpath);
2880 return NULL;
2881 }
2882 g_free(dirpath);
2883
2884 buf = g_malloc0(20);
2885 ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
8ce1ee46 2886 close(dirfd);
ef82b60b
HZ
2887 if (local_err) {
2888 g_free(buf);
2889 error_propagate(errp, local_err);
2890 return NULL;
2891 }
2892
2893 info = g_new0(GuestMemoryBlockInfo, 1);
2894 info->size = strtol(buf, NULL, 16); /* the unit is bytes */
2895
2896 g_free(buf);
2897
2898 return info;
a065aaa9
HZ
2899}
2900
e72c3f2e
MR
2901#else /* defined(__linux__) */
2902
77dbc81b 2903void qmp_guest_suspend_disk(Error **errp)
e72c3f2e 2904{
c6bd8c70 2905 error_setg(errp, QERR_UNSUPPORTED);
e72c3f2e
MR
2906}
2907
77dbc81b 2908void qmp_guest_suspend_ram(Error **errp)
e72c3f2e 2909{
c6bd8c70 2910 error_setg(errp, QERR_UNSUPPORTED);
e72c3f2e
MR
2911}
2912
77dbc81b 2913void qmp_guest_suspend_hybrid(Error **errp)
e72c3f2e 2914{
c6bd8c70 2915 error_setg(errp, QERR_UNSUPPORTED);
e72c3f2e
MR
2916}
2917
d35d4cb5 2918GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
e72c3f2e 2919{
c6bd8c70 2920 error_setg(errp, QERR_UNSUPPORTED);
d35d4cb5 2921 return NULL;
e72c3f2e
MR
2922}
2923
d2baff62
LE
2924GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
2925{
c6bd8c70 2926 error_setg(errp, QERR_UNSUPPORTED);
d2baff62
LE
2927 return NULL;
2928}
2929
cbb65fc2
LE
2930int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
2931{
c6bd8c70 2932 error_setg(errp, QERR_UNSUPPORTED);
cbb65fc2
LE
2933 return -1;
2934}
2935
215a2771
DB
2936void qmp_guest_set_user_password(const char *username,
2937 const char *password,
2938 bool crypted,
2939 Error **errp)
2940{
c6bd8c70 2941 error_setg(errp, QERR_UNSUPPORTED);
215a2771
DB
2942}
2943
a065aaa9
HZ
2944GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2945{
c6bd8c70 2946 error_setg(errp, QERR_UNSUPPORTED);
a065aaa9
HZ
2947 return NULL;
2948}
2949
2950GuestMemoryBlockResponseList *
2951qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2952{
c6bd8c70 2953 error_setg(errp, QERR_UNSUPPORTED);
a065aaa9
HZ
2954 return NULL;
2955}
2956
2957GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2958{
c6bd8c70 2959 error_setg(errp, QERR_UNSUPPORTED);
a065aaa9
HZ
2960 return NULL;
2961}
2962
d35d4cb5
MR
2963#endif
2964
2965#if !defined(CONFIG_FSFREEZE)
2966
46d4c572
TS
2967GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
2968{
c6bd8c70 2969 error_setg(errp, QERR_UNSUPPORTED);
46d4c572
TS
2970 return NULL;
2971}
2972
77dbc81b 2973GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
e72c3f2e 2974{
c6bd8c70 2975 error_setg(errp, QERR_UNSUPPORTED);
d35d4cb5
MR
2976
2977 return 0;
e72c3f2e
MR
2978}
2979
77dbc81b 2980int64_t qmp_guest_fsfreeze_freeze(Error **errp)
e72c3f2e 2981{
c6bd8c70 2982 error_setg(errp, QERR_UNSUPPORTED);
d35d4cb5
MR
2983
2984 return 0;
e72c3f2e
MR
2985}
2986
e99bce20
TS
2987int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
2988 strList *mountpoints,
2989 Error **errp)
2990{
c6bd8c70 2991 error_setg(errp, QERR_UNSUPPORTED);
e99bce20
TS
2992
2993 return 0;
2994}
2995
77dbc81b 2996int64_t qmp_guest_fsfreeze_thaw(Error **errp)
e72c3f2e 2997{
c6bd8c70 2998 error_setg(errp, QERR_UNSUPPORTED);
d35d4cb5
MR
2999
3000 return 0;
e72c3f2e 3001}
fed39564
TG
3002
3003GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
3004{
3005 error_setg(errp, QERR_UNSUPPORTED);
3006 return NULL;
3007}
3008
eab5fd59
PB
3009#endif /* CONFIG_FSFREEZE */
3010
3011#if !defined(CONFIG_FSTRIM)
e82855d9
JO
3012GuestFilesystemTrimResponse *
3013qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
eab5fd59 3014{
c6bd8c70 3015 error_setg(errp, QERR_UNSUPPORTED);
e82855d9 3016 return NULL;
eab5fd59 3017}
e72c3f2e
MR
3018#endif
3019
1281c08a
TS
3020/* add unsupported commands to the blacklist */
3021GList *ga_command_blacklist_init(GList *blacklist)
3022{
3023#if !defined(__linux__)
3024 {
3025 const char *list[] = {
3026 "guest-suspend-disk", "guest-suspend-ram",
3027 "guest-suspend-hybrid", "guest-network-get-interfaces",
0dd38a03
HZ
3028 "guest-get-vcpus", "guest-set-vcpus",
3029 "guest-get-memory-blocks", "guest-set-memory-blocks",
28d8dd35
BS
3030 "guest-get-memory-block-size", "guest-get-memory-block-info",
3031 NULL};
1281c08a
TS
3032 char **p = (char **)list;
3033
3034 while (*p) {
4bca81ce 3035 blacklist = g_list_append(blacklist, g_strdup(*p++));
1281c08a
TS
3036 }
3037 }
3038#endif
3039
3040#if !defined(CONFIG_FSFREEZE)
3041 {
3042 const char *list[] = {
3043 "guest-get-fsinfo", "guest-fsfreeze-status",
3044 "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
fed39564
TG
3045 "guest-fsfreeze-thaw", "guest-get-fsinfo",
3046 "guest-get-disks", NULL};
1281c08a
TS
3047 char **p = (char **)list;
3048
3049 while (*p) {
4bca81ce 3050 blacklist = g_list_append(blacklist, g_strdup(*p++));
1281c08a
TS
3051 }
3052 }
3053#endif
3054
3055#if !defined(CONFIG_FSTRIM)
4bca81ce 3056 blacklist = g_list_append(blacklist, g_strdup("guest-fstrim"));
1281c08a
TS
3057#endif
3058
2e4211ce
TG
3059 blacklist = g_list_append(blacklist, g_strdup("guest-get-devices"));
3060
1281c08a
TS
3061 return blacklist;
3062}
3063
e3d4d252
MR
3064/* register init/cleanup routines for stateful command groups */
3065void ga_command_state_init(GAState *s, GACommandState *cs)
3066{
7006b9cf 3067#if defined(CONFIG_FSFREEZE)
f22d85e9 3068 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
7006b9cf 3069#endif
e3d4d252 3070}
161a56a9 3071
e674605f
TG
3072#ifdef HAVE_UTMPX
3073
161a56a9
VF
3074#define QGA_MICRO_SECOND_TO_SECOND 1000000
3075
3076static double ga_get_login_time(struct utmpx *user_info)
3077{
3078 double seconds = (double)user_info->ut_tv.tv_sec;
3079 double useconds = (double)user_info->ut_tv.tv_usec;
3080 useconds /= QGA_MICRO_SECOND_TO_SECOND;
3081 return seconds + useconds;
3082}
3083
b90abbac 3084GuestUserList *qmp_guest_get_users(Error **errp)
161a56a9
VF
3085{
3086 GHashTable *cache = NULL;
95b3a8c8 3087 GuestUserList *head = NULL, **tail = &head;
161a56a9
VF
3088 struct utmpx *user_info = NULL;
3089 gpointer value = NULL;
3090 GuestUser *user = NULL;
161a56a9
VF
3091 double login_time = 0;
3092
3093 cache = g_hash_table_new(g_str_hash, g_str_equal);
3094 setutxent();
3095
3096 for (;;) {
3097 user_info = getutxent();
3098 if (user_info == NULL) {
3099 break;
3100 } else if (user_info->ut_type != USER_PROCESS) {
3101 continue;
3102 } else if (g_hash_table_contains(cache, user_info->ut_user)) {
3103 value = g_hash_table_lookup(cache, user_info->ut_user);
3104 user = (GuestUser *)value;
3105 login_time = ga_get_login_time(user_info);
3106 /* We're ensuring the earliest login time to be sent */
3107 if (login_time < user->login_time) {
3108 user->login_time = login_time;
3109 }
3110 continue;
3111 }
3112
95b3a8c8
EB
3113 user = g_new0(GuestUser, 1);
3114 user->user = g_strdup(user_info->ut_user);
3115 user->login_time = ga_get_login_time(user_info);
161a56a9 3116
95b3a8c8 3117 g_hash_table_insert(cache, user->user, user);
161a56a9 3118
95b3a8c8 3119 QAPI_LIST_APPEND(tail, user);
161a56a9
VF
3120 }
3121 endutxent();
3122 g_hash_table_destroy(cache);
3123 return head;
3124}
e674605f
TG
3125
3126#else
3127
3128GuestUserList *qmp_guest_get_users(Error **errp)
3129{
3130 error_setg(errp, QERR_UNSUPPORTED);
3131 return NULL;
3132}
3133
3134#endif
9848f797
TG
3135
3136/* Replace escaped special characters with theire real values. The replacement
3137 * is done in place -- returned value is in the original string.
3138 */
3139static void ga_osrelease_replace_special(gchar *value)
3140{
3141 gchar *p, *p2, quote;
3142
3143 /* Trim the string at first space or semicolon if it is not enclosed in
3144 * single or double quotes. */
3145 if ((value[0] != '"') || (value[0] == '\'')) {
3146 p = strchr(value, ' ');
3147 if (p != NULL) {
3148 *p = 0;
3149 }
3150 p = strchr(value, ';');
3151 if (p != NULL) {
3152 *p = 0;
3153 }
3154 return;
3155 }
3156
3157 quote = value[0];
3158 p2 = value;
3159 p = value + 1;
3160 while (*p != 0) {
3161 if (*p == '\\') {
3162 p++;
3163 switch (*p) {
3164 case '$':
3165 case '\'':
3166 case '"':
3167 case '\\':
3168 case '`':
3169 break;
3170 default:
3171 /* Keep literal backslash followed by whatever is there */
3172 p--;
3173 break;
3174 }
3175 } else if (*p == quote) {
3176 *p2 = 0;
3177 break;
3178 }
3179 *(p2++) = *(p++);
3180 }
3181}
3182
3183static GKeyFile *ga_parse_osrelease(const char *fname)
3184{
3185 gchar *content = NULL;
3186 gchar *content2 = NULL;
3187 GError *err = NULL;
3188 GKeyFile *keys = g_key_file_new();
3189 const char *group = "[os-release]\n";
3190
3191 if (!g_file_get_contents(fname, &content, NULL, &err)) {
3192 slog("failed to read '%s', error: %s", fname, err->message);
3193 goto fail;
3194 }
3195
3196 if (!g_utf8_validate(content, -1, NULL)) {
3197 slog("file is not utf-8 encoded: %s", fname);
3198 goto fail;
3199 }
3200 content2 = g_strdup_printf("%s%s", group, content);
3201
3202 if (!g_key_file_load_from_data(keys, content2, -1, G_KEY_FILE_NONE,
3203 &err)) {
3204 slog("failed to parse file '%s', error: %s", fname, err->message);
3205 goto fail;
3206 }
3207
3208 g_free(content);
3209 g_free(content2);
3210 return keys;
3211
3212fail:
3213 g_error_free(err);
3214 g_free(content);
3215 g_free(content2);
3216 g_key_file_free(keys);
3217 return NULL;
3218}
3219
3220GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
3221{
3222 GuestOSInfo *info = NULL;
3223 struct utsname kinfo;
339ca68b
TG
3224 GKeyFile *osrelease = NULL;
3225 const char *qga_os_release = g_getenv("QGA_OS_RELEASE");
9848f797
TG
3226
3227 info = g_new0(GuestOSInfo, 1);
3228
3229 if (uname(&kinfo) != 0) {
3230 error_setg_errno(errp, errno, "uname failed");
3231 } else {
3232 info->has_kernel_version = true;
3233 info->kernel_version = g_strdup(kinfo.version);
3234 info->has_kernel_release = true;
3235 info->kernel_release = g_strdup(kinfo.release);
3236 info->has_machine = true;
3237 info->machine = g_strdup(kinfo.machine);
3238 }
3239
339ca68b
TG
3240 if (qga_os_release != NULL) {
3241 osrelease = ga_parse_osrelease(qga_os_release);
3242 } else {
3243 osrelease = ga_parse_osrelease("/etc/os-release");
3244 if (osrelease == NULL) {
3245 osrelease = ga_parse_osrelease("/usr/lib/os-release");
3246 }
9848f797
TG
3247 }
3248
3249 if (osrelease != NULL) {
3250 char *value;
3251
3252#define GET_FIELD(field, osfield) do { \
3253 value = g_key_file_get_value(osrelease, "os-release", osfield, NULL); \
3254 if (value != NULL) { \
3255 ga_osrelease_replace_special(value); \
3256 info->has_ ## field = true; \
3257 info->field = value; \
3258 } \
3259} while (0)
3260 GET_FIELD(id, "ID");
3261 GET_FIELD(name, "NAME");
3262 GET_FIELD(pretty_name, "PRETTY_NAME");
3263 GET_FIELD(version, "VERSION");
3264 GET_FIELD(version_id, "VERSION_ID");
3265 GET_FIELD(variant, "VARIANT");
3266 GET_FIELD(variant_id, "VARIANT_ID");
3267#undef GET_FIELD
3268
3269 g_key_file_free(osrelease);
3270 }
3271
3272 return info;
3273}
2e4211ce
TG
3274
3275GuestDeviceInfoList *qmp_guest_get_devices(Error **errp)
3276{
3277 error_setg(errp, QERR_UNSUPPORTED);
3278
3279 return NULL;
3280}
548fb0da
MAL
3281
3282#ifndef HOST_NAME_MAX
3283# ifdef _POSIX_HOST_NAME_MAX
3284# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
3285# else
3286# define HOST_NAME_MAX 255
3287# endif
3288#endif
3289
3290char *qga_get_host_name(Error **errp)
3291{
3292 long len = -1;
3293 g_autofree char *hostname = NULL;
3294
3295#ifdef _SC_HOST_NAME_MAX
3296 len = sysconf(_SC_HOST_NAME_MAX);
3297#endif /* _SC_HOST_NAME_MAX */
3298
3299 if (len < 0) {
3300 len = HOST_NAME_MAX;
3301 }
3302
3303 /* Unfortunately, gethostname() below does not guarantee a
3304 * NULL terminated string. Therefore, allocate one byte more
3305 * to be sure. */
3306 hostname = g_new0(char, len + 1);
3307
3308 if (gethostname(hostname, len) < 0) {
3309 error_setg_errno(errp, errno,
3310 "cannot get hostname");
3311 return NULL;
3312 }
3313
3314 return g_steal_pointer(&hostname);
3315}