Compare commits

..

22 Commits

Author SHA1 Message Date
Pin
dc69f665eb readme 2024-05-21 23:18:56 -04:00
Pin
ec6fac8537 . 2024-05-21 23:17:21 -04:00
Pin
4dd55da7e7 debug 2024-05-21 23:11:14 -04:00
Pin
8fa0c4b259 magic 2024-05-21 21:36:50 -04:00
Pin
84fffca8e5 format 2024-05-21 21:27:47 -04:00
Pin
e4d58ff94b testing 2024-05-21 21:08:35 -04:00
Pin
fdd643c528 efhjksedjksejkn.fk 2024-05-14 22:31:05 -04:00
Pin
81bc834b26 yes i try i 2024-05-14 22:09:54 -04:00
e4d2076fa2 Send message to a worker 2024-04-04 22:59:10 -04:00
3f8bd314b6 Make a frontend in front of an actor 2024-03-30 17:14:49 -04:00
8be9dfc093 Add a clean target 2024-03-30 16:18:47 -04:00
f11569691f Move build target to first target
This makes it so you can just run make to build both the client and the daemon.
2024-03-30 16:18:33 -04:00
873ed765f4 Do not modify the argument we are given.
By duplicating it, we make it so popping frames off the message does not modify the argument.
This make sure the value remains useful to the caller.
2024-03-07 18:50:47 -05:00
2493f8916a Update usage
Tell users they should specify the name for an image.
2024-03-07 18:42:05 -05:00
bc7ccbd805 Move function implementations out of the header file. 2024-03-06 23:32:07 -05:00
5f98d369fa Prefix libguestfs-inspect functions with guestfs_inspect_.
The functions are also made non-static.
This is in preparation to moving the header function implementations to a .c file.
2024-03-06 23:32:07 -05:00
1d17e047b7 Add header guard to libguestfs-inspect.h 2024-03-06 23:22:29 -05:00
3c9564cb3e Use environment variable for the socket.
The default behavior is to create a socket file at /tmp/guestfs-inspect.sock.
If XDG_RUNTIME_DIR is set, that will be used instead of /tmp.

One could instead specify GUESTFS_INSPECT_ENDPOINT, which requires the full endpoint, as specified by: https://libzmq.readthedocs.io/en/zeromq3-x/zmq_connect.html

You will likely want to use ipc://, but you can probably use tcp:// or (e)pgm:// if that is appropriate.
2024-03-06 23:22:29 -05:00
ba3ac50325 Remove unused include 2024-03-06 19:25:05 -05:00
465d6f0cd4 Set workdir in the Dockerfile 2024-03-06 19:24:34 -05:00
1378a5a31a Free the worker 2024-03-06 19:24:34 -05:00
Pin
46d9500d3a small fix 2024-03-05 20:40:11 -05:00
9 changed files with 395 additions and 140 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ guestfs-inspect
guestfs-inspectd guestfs-inspectd
*~ *~
*.qcow2 *.qcow2
venv/

View File

@@ -1,4 +1,11 @@
FROM debian FROM debian as builder
RUN apt update && apt upgrade -y RUN apt update && apt upgrade -y
RUN apt install -y libczmq-dev libguestfs-dev gcc valgrind gdb make pkg-config RUN apt install -y libczmq-dev libguestfs-dev gcc valgrind gdb make pkg-config
COPY . /opt
WORKDIR /opt
FROM builder as compile
RUN make

View File

@@ -1,7 +1,17 @@
build: daemon client
debug: daemon-debug client-debug
daemon: daemon:
gcc guestfs-inspectd.c -o guestfs-inspectd `pkg-config libguestfs libczmq --cflags --libs` gcc -Wall guestfs-inspectd.c libguestfs-inspect.c -o guestfs-inspectd `pkg-config libguestfs libczmq --cflags --libs`
client: client:
gcc -g guestfs-inspect.c -o guestfs-inspect `pkg-config libguestfs libczmq --cflags --libs` gcc -Wall guestfs-inspect.c libguestfs-inspect.c -o guestfs-inspect `pkg-config libguestfs libczmq --cflags --libs`
build: daemon client daemon-debug:
gcc -ggdb3 -Wall guestfs-inspectd.c libguestfs-inspect.c -o guestfs-inspectd `pkg-config libguestfs libczmq --cflags --libs`
client-debug:
gcc -ggdb3 -Wall guestfs-inspect.c libguestfs-inspect.c -o guestfs-inspect `pkg-config libguestfs libczmq --cflags --libs`
clean:
rm guestfs-inspect guestfs-inspectd

17
README.md Normal file
View File

@@ -0,0 +1,17 @@
# Edda
```
,ggggggg,
,dP""""""Y8b 8I 8I
d8' a Y8 8I 8I
88 "Y8P' 8I 8I
`8baaaa 8I 8I
,d8P"""" ,gggg,8I ,gggg,8I ,gggg,gg
d8" dP" "Y8I dP" "Y8I dP" "Y8I
Y8, i8' ,8I i8' ,8I i8' ,8I
`Yba,,_____, ,d8, ,d8b,,d8, ,d8b,,d8, ,d8b,
`"Y8888888 P"Y8888P"`Y8P"Y8888P"`Y8P"Y8888P"`Y8
```

21
client.py Normal file
View File

@@ -0,0 +1,21 @@
import zmq
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect('ipc:///run/user/1000/guestfs-inspect.sock')
tt = 1
tt_size = 1
message = "test"
socket.send(message.encode('utf-8'), flags=zmq.SNDMORE)
socket.send(tt.to_bytes(4, 'little'), flags=zmq.SNDMORE)
socket.send(tt_size.to_bytes(8, 'little'), flags=zmq.SNDMORE)
socket.send('/etc/os-release'.encode('utf-8'), flags=zmq.SNDMORE)
socket.send(''.encode('utf-8'))
message = socket.recv()
print(message.decode('utf-8'))
socket.close()
context.destroy()

View File

@@ -8,7 +8,7 @@
#define STREQ(a, b) (strcmp((a), (b)) == 0) #define STREQ(a, b) (strcmp((a), (b)) == 0)
void print_help(char *); void print_help(char *);
enum guestfs_inspect_command_const parse_command(char *); enum guestfs_inspect_command_const parse_command(const char *);
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc == 1) { if (argc == 1) {
@@ -16,7 +16,7 @@ int main(int argc, char **argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
char *ep = endpoint(); char *ep = guestfs_inspect_endpoint();
zsock_t *daemon = zsock_new_req(ep); zsock_t *daemon = zsock_new_req(ep);
free(ep); free(ep);
@@ -40,7 +40,7 @@ int main(int argc, char **argv) {
break; break;
} }
zmsg_t *msg = command_to_zmsg(command); zmsg_t *msg = guestfs_inspect_command_to_zmsg(command);
zmsg_send(&msg, daemon); zmsg_send(&msg, daemon);
zmsg_t *rep = zmsg_recv(daemon); zmsg_t *rep = zmsg_recv(daemon);
@@ -62,7 +62,7 @@ int main(int argc, char **argv) {
zmsg_destroy(&msg); zmsg_destroy(&msg);
zmsg_destroy(&rep); zmsg_destroy(&rep);
zsock_destroy(&daemon); zsock_destroy(&daemon);
command_destroy(&command); guestfs_inspect_command_destroy(&command);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -74,7 +74,7 @@ void print_help(char *name) {
printf(" cat <path>\n"); printf(" cat <path>\n");
} }
enum guestfs_inspect_command_const parse_command(char *input) { enum guestfs_inspect_command_const parse_command(const char *input) {
if (STREQ(input, "ls")) { if (STREQ(input, "ls")) {
return GUESTFS_COMMAND_LS; return GUESTFS_COMMAND_LS;
} else if (STREQ(input, "cat")) { } else if (STREQ(input, "cat")) {

View File

@@ -2,15 +2,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <czmq.h> #include <czmq.h>
#include <zactor.h>
#include <zmsg.h> #include <zmsg.h>
#include <zactor.h>
#include <guestfs.h> #include <guestfs.h>
#include <time.h>
#include "libguestfs-inspect.h" #include "libguestfs-inspect.h"
#define STREQ(a, b) (strcmp((a), (b)) == 0) #define STREQ(a, b) (strcmp((a), (b)) == 0)
static void *worker_task(zsock_t*, char*); static void worker_task(zsock_t*, const char*);
static int compare_key_len(const void*, const void*); static int compare_key_len(const void*, const void*);
static int count_mountpoints(char *const *argv); static int count_mountpoints(char *const *argv);
@@ -21,15 +22,32 @@ static int compare_key_len(const void *p1, const void *p2) {
return strlen(key1) - strlen(key2); return strlen(key1) - strlen(key2);
} }
static void print_intro() {
printf("\n"
"\n"
" ,ggggggg,\n"
" ,dP\"\"\"\"\"\"Y8b 8I 8I\n"
" d8' a Y8 8I 8I\n"
" 88 \"Y8P\' 8I 8I\n"
" `8baaaa 8I 8I\n"
",d8P\"\"\"\" ,gggg,8I ,gggg,8I ,gggg,gg\n"
"d8\" dP\" \"Y8I dP\" \"Y8I dP\" \"Y8I\n"
"Y8, i8' ,8I i8' ,8I i8' ,8I\n"
"`Yba,,_____, ,d8, ,d8b,,d8, ,d8b,,d8, ,d8b,\n"
" `\"Y8888888 P\"Y8888P\"`Y8P\"Y8888P\"`Y8P\"Y8888P\"`Y8\n"
"\n");
}
static int count_mountpoints(char *const *argv) { static int count_mountpoints(char *const *argv) {
size_t c; size_t c;
for (c = 0; argv[c]; c++) {} for (c = 0; argv[c]; c++) {}
return c; return c;
} }
static void cat_file(guestfs_h *g, char *file_path, char **file_content, size_t *file_size) { static void cat_file(guestfs_h *g, const char *file_path, char **file_content, size_t *file_size) {
assert((*file_content) == NULL);
if (guestfs_is_file_opts(g, file_path, GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) { if (guestfs_is_file_opts(g, file_path, GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
printf("path:: %s\n", file_path);
(*file_content) = guestfs_read_file(g, file_path, file_size); (*file_content) = guestfs_read_file(g, file_path, file_size);
if ((*file_content) == NULL) { if ((*file_content) == NULL) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -38,7 +56,8 @@ static void cat_file(guestfs_h *g, char *file_path, char **file_content, size_t
return; return;
} }
static void init_guestfs(guestfs_h *g, char *disk_path) { static guestfs_h* init_guestfs(const char *disk_path) {
guestfs_h *g = NULL;
char **roots, **mountpoints; char **roots, **mountpoints;
char *root; char *root;
size_t i, j; size_t i, j;
@@ -83,29 +102,33 @@ static void init_guestfs(guestfs_h *g, char *disk_path) {
free(root); free(root);
} }
free(roots); free(roots);
return g;
printf("Finished initializing guestfs\n");
} }
static void *worker_task(zsock_t *pipe, char *disk_path) { static void worker_task(zsock_t *pipe, const char *disk_path) {
guestfs_h *g = NULL; guestfs_h *g;
g = init_guestfs(disk_path);
//init_guestfs(g, disk_path); zsock_t *worker = zsock_new_dealer("inproc://workers");
// ZeroMQ Opens here // ZeroMQ Opens here
zsock_signal(pipe, 0); zsock_signal(pipe, 0);
while (true) { while (true) {
zmsg_t *msg = zmsg_recv(pipe); zmsg_t *msg = zmsg_recv(pipe);
if (!msg) { if (!msg) {
break; break;
} }
// Process message
// do something here zframe_t *client_id = zmsg_pop(msg);
printf("Received a message in the worker\n"); // Checking for term message
if (zframe_streq(client_id, "$TERM")) {
zframe_destroy(&client_id);
zmsg_destroy(&msg);
break;
}
printf("Size: %zu\tContent size: %zu\n", zmsg_size(msg), zmsg_content_size(msg)); struct guestfs_inpsect_command *command = guestfs_inspect_zmsg_to_command(msg);
struct guestfs_inpsect_command *command = zmsg_to_command(msg);
zmsg_t *reply = zmsg_new(); zmsg_t *reply = zmsg_new();
if (!reply) { if (!reply) {
printf("wuddahec\n"); printf("wuddahec\n");
@@ -113,53 +136,187 @@ static void *worker_task(zsock_t *pipe, char *disk_path) {
} }
switch (command->command) { switch (command->command) {
case GUESTFS_COMMAND_LS: case GUESTFS_COMMAND_LS:;
zmsg_pushstr(reply, "From worker!"); zmsg_pushstr(reply, "From worker! -- not implemented");
break; break;
case GUESTFS_COMMAND_CAT: case GUESTFS_COMMAND_CAT:;
char *res; char *res = NULL;
size_t s; size_t s = 0;
puts("catting file..."); cat_file(g, command->args.cat.paths[0], &res, &s);
//cat_file(g, command->args.cat.paths[0], &res, &s); zmsg_addmem(reply, res, s);
init_guestfs(g, disk_path); free(res);
printf("STATUS::%d\n", guestfs_get_state(g)); break;
if(guestfs_is_file_opts(g, "/etc/os-release", GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) { default:;
res = guestfs_read_file(g, "/etc/os-release", &s); zmsg_pushstr(reply, "Unknown command");
} break;
puts("Done catting file contents...");
zmsg_addmem(reply, res, s);
break;
} }
// Sending reply // Sending reply
zmsg_send(&reply, pipe); zmsg_pushstr(reply, "");
zmsg_prepend(reply, &client_id);
zmsg_send(&reply, worker);
command_destroy(&command); guestfs_inspect_command_destroy(&command);
zframe_destroy(&client_id);
zmsg_destroy(&msg); zmsg_destroy(&msg);
zmsg_destroy(&reply); zmsg_destroy(&reply);
} }
guestfs_shutdown(g);
guestfs_close(g); guestfs_close(g);
zsock_destroy(&worker);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
typedef struct {
char *name;
zactor_t *worker;
} zactor_worker_map;
char *strdup(const char *);
void mapping_zactor_worker(const char *name, zactor_t *worker, zactor_worker_map **map, size_t mapper_size) {
map[mapper_size - 1] = malloc(sizeof(zactor_worker_map));
(*map[mapper_size - 1]).name = strdup(name);
(*map[mapper_size - 1]).worker = worker;
return;
}
zactor_t * zactor_worker_lookup(char *name, zactor_worker_map **map, size_t mapper_size) {
size_t i = 0;
for (i = 0; i < mapper_size; i++) {
if (strcmp((*map[i]).name, name) == 0) {
return map[i]->worker;
}
}
return NULL;
}
static void log_message(const char *message) {
time_t ltime;
struct tm *result;
char *stime;
ltime = time(NULL);
result = localtime(&ltime);
stime = asctime(result);
strtok(stime, "\n");
printf("[%s] %s\n", stime, message);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
printf("Usage: %s <disk-path> ...\n", argv[0]); printf("Usage: %s <disk-path>:<name> ...\n", argv[0]);
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
char *path = strtok(argv[1], ":"); print_intro();
char *name = strtok(NULL, ":");
printf("name: '%s'\n", name);
char *ep = endpoint(); // Zactor setup
printf("ep: %s\n", ep); size_t worker_map_size = 0;
zsock_t *worker = zsock_new_rep(ep); zactor_worker_map **worker_map = NULL;
log_message("Starting Workers");
for (int i = 0; i < argc - 1; i++) {
worker_map_size++;
worker_map = realloc(worker_map, sizeof(zactor_worker_map *) * worker_map_size);
char *path = strtok(argv[i+1], ":");
char *name = strtok(NULL, ":");
mapping_zactor_worker(name, zactor_new((void *)worker_task, path), worker_map, worker_map_size);
}
if (worker_map == NULL) {
log_message("Worker map was empty");
exit(EXIT_FAILURE);
}
// Setup daemon ipc endpoint
char *ep = guestfs_inspect_endpoint();
// Setting up endpoint log message
char *ep_log = (char *)malloc((strlen(ep) * sizeof(char)) + 32);
// Sending endpoint log message
sprintf(ep_log, "Endpoint: %s", ep); // NOLINT
log_message(ep_log);
free(ep_log);
// Setup ZMQ routers
zsock_t *frontend = zsock_new(ZMQ_ROUTER);
zsock_bind(frontend, "%s", ep);
free(ep); free(ep);
worker_task(worker, path); zsock_t *backend = zsock_new(ZMQ_ROUTER);
zsock_bind(backend, "inproc://workers");
return EXIT_SUCCESS; // Connecting frontend to backend
zpoller_t *poller = zpoller_new(frontend, backend, NULL);
assert(poller);
log_message("Server listening for requests");
zframe_t *message_pop = NULL;
while (true) {
void *sock = zpoller_wait(poller, -1);
if (!sock) {
break;
}
if (sock == frontend) {
zmsg_t *msg = zmsg_recv(frontend);
// reply id
zframe_t *identity = zmsg_pop(msg);
// Null frame
message_pop = zmsg_pop(msg);
// Destroy immediately
zframe_destroy(&message_pop);
struct guestfs_inpsect_command *c = guestfs_inspect_zmsg_to_command(msg);
if (c == NULL) {
log_message("Error creating inspect command");
zmsg_destroy(&msg);
zframe_destroy(&identity);
continue;
}
zactor_t *zactor_tmp = zactor_worker_lookup(c->name, worker_map, worker_map_size);
if (zactor_tmp != NULL) {
// send request to worker
zmsg_prepend(msg, &identity);
zactor_send(zactor_tmp, &msg);
} else {
// add failure response
}
zactor_tmp = NULL;
guestfs_inspect_command_destroy(&c);
zmsg_destroy(&msg);
zframe_destroy(&identity);
} else if (sock == backend) {
zmsg_t *msg = zmsg_recv(backend);
message_pop = zmsg_pop(msg); // Removing backend id
// Destroy immediately
zframe_destroy(&message_pop);
zmsg_send(&msg, frontend);
zmsg_destroy(&msg);
} else {
log_message("Socket found from unknown zsock");
}
}
log_message("Cleaning up workers");
// Cleanup
for (size_t i = 0; i < worker_map_size; i++) {
zactor_destroy(&worker_map[i]->worker);
free(worker_map[i]->name);
free(worker_map[i]);
}
free(worker_map);
zpoller_destroy(&poller);
zsock_destroy(&frontend);
zsock_destroy(&backend);
exit(EXIT_SUCCESS);
} }

122
libguestfs-inspect.c Normal file
View File

@@ -0,0 +1,122 @@
#include <czmq.h>
#include "libguestfs-inspect.h"
char *guestfs_inspect_endpoint() {
const char *guestfs_inspect_endpoint = getenv("GUESTFS_INSPECT_ENDPOINT");
const char *socket_file_name = "/guestfs-inspect.sock";
char *res = NULL;
if (guestfs_inspect_endpoint) {
res = malloc(strlen(guestfs_inspect_endpoint) + 1);
strcpy(res, guestfs_inspect_endpoint);
} else {
const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
if (xdg_runtime_dir) {
res = malloc(strlen(xdg_runtime_dir) + strlen(socket_file_name) + strlen("ipc://") + 1);
strcpy(res, "ipc://");
strcat(res, xdg_runtime_dir);
strcat(res, socket_file_name);
} else {
const char *tmp_dir = "/tmp";
res = malloc(strlen(tmp_dir) + strlen(socket_file_name) + strlen("ipc://") + 1);
strcpy(res, "ipc://");
strcat(res, tmp_dir);
strcat(res, socket_file_name);
}
}
return res;
}
zmsg_t *guestfs_inspect_command_to_zmsg(const struct guestfs_inpsect_command *command) {
zmsg_t *res = zmsg_new();
zmsg_addstr(res, command->name);
zmsg_addmem(res, &(command->command), sizeof(command->command));
switch (command->command) {
case GUESTFS_COMMAND_LS:
zmsg_addmem(res, &(command->args.ls.paths_length), sizeof(command->args.ls.paths_length));
for (size_t i = 0; i < (command->args.ls.paths_length); i++) {
zmsg_addstr(res, command->args.ls.paths[i]);
}
break;
case GUESTFS_COMMAND_CAT:
zmsg_addmem(res, &(command->args.cat.paths_length), sizeof(command->args.cat.paths_length));
for (size_t i = 0; i < (command->args.cat.paths_length); i++) {
zmsg_addstr(res, command->args.cat.paths[i]);
}
break;
}
return res;
}
struct guestfs_inpsect_command *guestfs_inspect_zmsg_to_command(zmsg_t *external_msg) {
// This way we do not modify the argument we are given.
zmsg_t *msg = zmsg_dup(external_msg);
struct guestfs_inpsect_command *res = malloc(sizeof(struct guestfs_inpsect_command));
if (!(zmsg_size(msg) > 2)) {
free(res);
zmsg_destroy(&msg);
return NULL;
}
res->name = zmsg_popstr(msg);
zframe_t *next = zmsg_pop(msg);
res->command = *(zframe_data(next));
zframe_destroy(&next);
switch (res->command) {
case GUESTFS_COMMAND_LS:
next = zmsg_pop(msg);
res->args.ls.paths_length = *(zframe_data(next));
free(next);
res->args.ls.paths = calloc(res->args.ls.paths_length, sizeof(char *));
for (size_t i = 0; i < res->args.ls.paths_length; i++) {
res->args.ls.paths[i] = zmsg_popstr(msg);
}
break;
case GUESTFS_COMMAND_CAT:
next = zmsg_pop(msg);
res->args.cat.paths_length = *(zframe_data(next));
free(next);
res->args.cat.paths = calloc(res->args.cat.paths_length, sizeof(char *));
for (size_t i = 0; i < res->args.cat.paths_length; i++) {
res->args.cat.paths[i] = zmsg_popstr(msg);
}
break;
default:
printf("Command not found\n");
}
zmsg_destroy(&msg);
return res;
}
void guestfs_inspect_command_destroy(struct guestfs_inpsect_command **c) {
free((*c)->name);
switch ((*c)->command) {
case GUESTFS_COMMAND_LS:
for (size_t i = 0; i < (*c)->args.ls.paths_length; i++) {
free((*c)->args.ls.paths[i]);
}
free((*c)->args.ls.paths);
break;
case GUESTFS_COMMAND_CAT:
for (size_t i = 0; i < (*c)->args.cat.paths_length; i++) {
free((*c)->args.cat.paths[i]);
}
free((*c)->args.cat.paths);
break;
}
free(*c);
*c = NULL;
}

View File

@@ -1,3 +1,6 @@
#ifndef LIBGUESTFS_INSPECT_H
#define LIBGUESTFS_INSPECT_H
#include <czmq.h> #include <czmq.h>
enum guestfs_inspect_command_const { enum guestfs_inspect_command_const {
@@ -25,92 +28,9 @@ struct guestfs_inpsect_command {
} args; } args;
}; };
static char *endpoint() { char *guestfs_inspect_endpoint(void);
// TODO: This should be based on GUESTFS_INSPECT_ENDPOINT, or XDG_RUNTIME_DIR if the former is not set, and default to a sensible path if neither are set. zmsg_t *guestfs_inspect_command_to_zmsg(const struct guestfs_inpsect_command *command);
const char* ep = "ipc:///tmp/guestfs-inspect.sock"; struct guestfs_inpsect_command *guestfs_inspect_zmsg_to_command(zmsg_t *msg);
char *res = malloc(strlen(ep) + 1); void guestfs_inspect_command_destroy(struct guestfs_inpsect_command **c);
strcpy(res, ep);
return res;
}
static zmsg_t *command_to_zmsg(struct guestfs_inpsect_command *command) { #endif // LIBGUESTFS_INSPECT_H
zmsg_t *res = zmsg_new();
zmsg_addstr(res, command->name);
zmsg_addmem(res, &(command->command), sizeof(command->command));
switch (command->command) {
case GUESTFS_COMMAND_LS:
zmsg_addmem(res, &(command->args.ls.paths_length), sizeof(command->args.ls.paths_length));
for (size_t i = 0; i < (command->args.ls.paths_length); i++) {
zmsg_addstr(res, command->args.ls.paths[i]);
}
break;
case GUESTFS_COMMAND_CAT:
zmsg_addmem(res, &(command->args.cat.paths_length), sizeof(command->args.cat.paths_length));
for (size_t i = 0; i < (command->args.cat.paths_length); i++) {
zmsg_addstr(res, command->args.cat.paths[i]);
}
break;
}
return res;
}
static struct guestfs_inpsect_command *zmsg_to_command(zmsg_t *msg) {
struct guestfs_inpsect_command *res = malloc(sizeof(struct guestfs_inpsect_command));
res->name = zmsg_popstr(msg);
zframe_t *next = zmsg_pop(msg);
res->command = *(zframe_data(next));
free(next);
switch (res->command) {
case GUESTFS_COMMAND_LS:
next = zmsg_pop(msg);
res->args.ls.paths_length = *(zframe_data(next));
free(next);
res->args.ls.paths = calloc(res->args.ls.paths_length, sizeof(char *));
for (size_t i = 0; i < res->args.ls.paths_length; i++) {
res->args.ls.paths[i] = zmsg_popstr(msg);
}
break;
case GUESTFS_COMMAND_CAT:
next = zmsg_pop(msg);
res->args.cat.paths_length = *(zframe_data(next));
free(next);
res->args.cat.paths = calloc(res->args.cat.paths_length, sizeof(char *));
for (size_t i = 0; i < res->args.cat.paths_length; i++) {
res->args.cat.paths[i] = zmsg_popstr(msg);
}
break;
}
return res;
}
static void command_destroy(struct guestfs_inpsect_command **c) {
free((*c)->name);
switch ((*c)->command) {
case GUESTFS_COMMAND_LS:
for (size_t i = 0; i < (*c)->args.ls.paths_length; i++) {
free((*c)->args.ls.paths[i]);
}
free((*c)->args.ls.paths);
break;
case GUESTFS_COMMAND_CAT:
for (size_t i = 0; i < (*c)->args.cat.paths_length; i++) {
free((*c)->args.cat.paths[i]);
}
free((*c)->args.cat.paths);
break;
}
free(*c);
*c = NULL;
}