/* * Copyright 2023 United States Government * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "config.h" #include #include "graph-core.h" #include #include #include #ifdef HAVE_LIBREADLINE # if defined(HAVE_READLINE_READLINE_H) # include # elif defined(HAVE_READLINE_H) # include # else /* !defined(HAVE_READLINE_H) */ extern char *readline (char *prompt); # endif /* !defined(HAVE_READLINE_H) */ #else /* !defined(HAVE_READLINE_READLINE_H) */ /* no readline */ static char *readline(char *prompt) { char *buf = NULL; size_t bufsz = 0; size_t length = 0; printf("%s", prompt); ssize_t read = getline(&buf, &bufsz, stdin); if(read < 0) { free(buf); return NULL; } // Clean newline which appended to the path length = strlen(buf); if (buf[length-1] == '\n') { buf[length-1] = '\0'; } return buf; } #endif /* HAVE_LIBREADLINE */ #ifdef HAVE_READLINE_HISTORY # if defined(HAVE_READLINE_HISTORY_H) # include # elif defined(HAVE_HISTORY_H) # include # else /* !defined(HAVE_HISTORY_H) */ extern void add_history (); # endif /* defined(HAVE_READLINE_HISTORY_H) */ #else /* no history */ static inline void add_history(char *line UNUSED) {} #endif /* HAVE_READLINE_HISTORY */ #include #include "graph-fs-private.h" #include #define PROMPT_SIZE 32 /** * Copied from ../dummy_types.[ch] */ typedef struct simple_address { address a; uint32_t addr; } simple_address; typedef struct dummy_measurement_data { measurement_data d; uint32_t x; } dummy_measurement_data; address *alloc_simple_address(); void free_simple_address(address *a); address *simple_copy_address(const address *a); gboolean simple_address_equal(const address *a, const address *b); guint simple_address_hash(const address *a); char *serialize_simple_address(const address *a); address *parse_simple_address(const char *str, size_t); address *simple_address_from_human_readable(const char *str); measurement_data *alloc_dummy_measurement_data(); void free_dummy_measurement_data(measurement_data *d); measurement_data *copy_dummy_measurement_data(measurement_data *d); int serialize_dummy_measurement_data(measurement_data *d, char **, size_t*); int unserialize_dummy_measurement_data(char *sd, size_t sd_size, measurement_data **out); static int dummy_measurement_data_get_feature(measurement_data *d, char *feature, GList **out); target_type dummy_target_type = { .magic = 0xbeefdead, .name = "dummy" }; address_space simple_address_space = { .magic = 0xdeadbeef, .alloc_address = alloc_simple_address, .copy_address = simple_copy_address, .free_address = free_simple_address, .serialize_address = serialize_simple_address, .parse_address = parse_simple_address, .address_equal = simple_address_equal, .address_hash = simple_address_hash, .human_readable = serialize_simple_address, .from_human_readable = simple_address_from_human_readable }; measurement_type dummy_measurement_type = { .name = "dummy", .magic = 0xdeadbeef, .alloc_data = alloc_dummy_measurement_data, .copy_data = copy_dummy_measurement_data, .free_data = free_dummy_measurement_data, .serialize_data = serialize_dummy_measurement_data, .unserialize_data = unserialize_dummy_measurement_data, .get_feature = dummy_measurement_data_get_feature }; measurement_data *alloc_dummy_measurement_data() { dummy_measurement_data *d = malloc(sizeof(*d)); if(d) { d->d.type = &dummy_measurement_type; d->x = 0; } else { return NULL; } return &d->d; } void free_dummy_measurement_data(measurement_data *d) { free(d); } measurement_data *copy_dummy_measurement_data(measurement_data *d) { dummy_measurement_data *dd = (dummy_measurement_data *)d; dummy_measurement_data *res = (dummy_measurement_data *)alloc_measurement_data(&dummy_measurement_type); if(res) res->x = dd->x; return &res->d; } int serialize_dummy_measurement_data(measurement_data *d, char **sd, size_t*size_sd) { int ret_val = 0; dummy_measurement_data *dd = (dummy_measurement_data *)d; char *buf = malloc(9); if(buf) { sprintf(buf, "%08"PRIx32, dd->x); *sd = buf; *size_sd = 9; } else { *sd = NULL; *size_sd = 0; ret_val = -1; // XXX: find right errno value !! } return ret_val; } int unserialize_dummy_measurement_data(char *sd, size_t sd_size UNUSED, measurement_data **out) { int ret_val = 0; dummy_measurement_data *d = (dummy_measurement_data *)alloc_measurement_data(&dummy_measurement_type); if(d) { sscanf((char*)sd, "%08"PRIx32, &d->x); } *out = (measurement_data*)d; return ret_val; } address *alloc_simple_address() { simple_address *a = malloc(sizeof(simple_address)); if(a) { a->a.space = &simple_address_space; } else { return NULL; } return &a->a; } void free_simple_address(address *a) { free(a); } char *serialize_simple_address(const address *a) { char *buf = malloc(9); if(buf) sprintf(buf, "%08"PRIx32, ((const simple_address*)a)->addr); return buf; } address *parse_simple_address(const char *str, size_t maxbytes) { address *a; if(maxbytes != 9) { return NULL; } if((a = alloc_address(&simple_address_space)) != NULL) { sscanf(str, "%08"PRIx32, &((simple_address*)a)->addr); } return a; } address *simple_address_from_human_readable(const char *str) { return parse_simple_address(str, strlen(str)+1); } address *simple_copy_address(const address *a) { address *res = alloc_address(&simple_address_space); if(res == NULL) { return NULL; } simple_address *sa = container_of(res, simple_address, a); sa->addr = ((simple_address *)a)->addr; return &sa->a; } gboolean simple_address_equal(const address *a, const address *b) { return ((simple_address *)a)->addr == ((simple_address *)b)->addr; } guint simple_address_hash(const address *a) { return (guint)((simple_address *)a)->addr; } static int dummy_measurement_data_get_feature(measurement_data *d, char *feature, GList **out) { if(strcmp(feature, "x") == 0) { char *buf = g_strdup_printf("0x%08"PRIx32, ((dummy_measurement_data *)d)->x); if(buf == NULL) { return -1; } *out = g_list_append(NULL, buf); return 0; } else { dlog(4, "Warning: no such feature \"%s\" for measurement_type dummy\n", feature); } return -1; } static void print_edge(measurement_graph *graph, edge_id_t e) { node_id_t src = measurement_edge_get_source(graph, e); node_id_t dst = measurement_edge_get_destination(graph, e); printf(ID_FMT": "ID_FMT " -> "ID_FMT"\n", e, src, dst); } static void print_node(measurement_graph *graph, node_id_t n) { target_type *ttype = measurement_node_get_target_type(graph, n); address *node_address = measurement_node_get_address(graph, n); char *address_str = node_address ? address_human_readable(node_address) : NULL; if(ttype && address_str) { printf(ID_FMT": (%s *)%s\n", n, ttype->name, address_str); free(address_str); } else { printf(ID_FMT"\n", n); } free_address(node_address); } static void print_address_space(const address_space *s, void *arg UNUSED) { printf(MAGIC_FMT"\t%s\n", s->magic, s->name); } static void print_target_type(const target_type *t, void *arg UNUSED) { printf(MAGIC_FMT"\t%s\n", t->magic, t->name); } static void print_measurement_type(const measurement_type *t, void *arg UNUSED) { printf(MAGIC_FMT"\t%s\n", t->magic, t->name); } int main(int __attribute__((unused)) argc, char __attribute__((unused)) *argv[]) { int done=0; char prompt[PROMPT_SIZE] = "graph()> "; measurement_graph *graph = NULL; register_target_type(&dummy_target_type); register_measurement_type(&dummy_measurement_type); register_address_space(&simple_address_space); while(!done) { char *line = readline(prompt); char *cmd, *args; if(!line) { fprintf(stderr, "Error: readline() failed.\n"); break; } cmd = line; while(isspace(*cmd)) cmd++; if(cmd[0] == '\0') { free(line); continue; } add_history(line); if(cmd[0] == '!') { if(system(&cmd[1]) != 0) { fprintf(stderr, "Warning: command \"%s\" failed\n", &cmd[1]); } goto next; } args = cmd; while(!isspace(*args) && *args != '\0') { args++; } if(isspace(*args)) { *args='\0'; args++; } /* we now have a buffer like: * line = " cmd\0arg1 arg2...\0" * ^ ^ * cmd args */ if(strcmp(cmd, "quit") == 0) { done = 1; } else if(strcmp(cmd, "types") == 0) { char *ptr = args; void *lib; while((!isspace(*ptr)) && (*ptr != '\0')) { ptr++; } if(*ptr == '\0') { fprintf(stderr, "Error: types ...\n"); goto next; } *ptr = '\0'; lib = dlopen(args, RTLD_NOW | RTLD_LOCAL); if(lib == NULL) { fprintf(stderr, "dlopen(\"%s\") failed\n", args); goto next; } args = ptr+1; while(*args != '\0') { int done = 0; while(isspace(*args)) { args++; if(*args == '\0') goto next; } ptr = args+1; while((!isspace(*ptr)) && *ptr != '\0') { ptr++; } if(*ptr == '\0') done = 1; *ptr = '\0'; int (*reg)(void) = dlsym(lib, args); if(reg == NULL) { fprintf(stderr, "failed to find symbol %s in library\n", args); } else { if(reg() != 0) { fprintf(stderr, "registration function %s returned nonzero\n", args); } } if(!done) { *ptr = ' '; } args = ptr; } } else if(strcmp(cmd, "ls-address-spaces") == 0) { foreach_address_space(&print_address_space, NULL); } else if(strcmp(cmd, "ls-target-types") == 0) { foreach_target_type(&print_target_type, NULL); } else if(strcmp(cmd, "ls-measurement-types") == 0) { foreach_measurement_type(&print_measurement_type, NULL); } else if(strcmp(cmd, "new") == 0) { if(graph != NULL) { destroy_measurement_graph(graph); } graph = create_measurement_graph(NULL); if(graph != NULL) { printf("Graph created at %s\n", graph->path); snprintf(prompt, PROMPT_SIZE, "graph(%.22s)> ", graph->path); } else { fprintf(stderr, "Failed to create graph\n"); } } else if(strcmp(cmd, "map") == 0) { if(graph != NULL) { destroy_measurement_graph(graph); snprintf(prompt, PROMPT_SIZE, "graph()> "); } char *ptr = args; while((!isspace(*ptr)) && (*ptr != '\0')) { ptr++; } *ptr = '\0'; if(map_measurement_graph(args, &graph) != 0) { fprintf(stderr, "Error: map \n"); graph = NULL; goto next; } snprintf(prompt, PROMPT_SIZE, "graph(%.22s)> ", graph->path); } else if(strcmp(cmd, "delete") == 0) { destroy_measurement_graph(graph); graph = NULL; snprintf(prompt, PROMPT_SIZE, "graph()> "); } else if(strcmp(cmd, "add-node") == 0) { address_space *space; magic_t type_magic; magic_t space_magic; char *addr_str; int offset; measurement_variable v; node_id_t n = INVALID_NODE_ID; int rc; if(graph == NULL) { fprintf(stderr, "Error: must create a graph with 'new' first\n"); goto next; } if(sscanf(args, " "MAGIC_FMT" "MAGIC_FMT" %n", &type_magic, &space_magic, &offset) != 2) { fprintf(stderr, "Error: add-node
\n"); goto next; } addr_str = args + offset; v.type = find_target_type(type_magic); if(v.type == NULL) { fprintf(stderr, "Error: No type found with magic "MAGIC_FMT"\n", type_magic); goto next; } space = find_address_space(space_magic); if(space == NULL) { fprintf(stderr, "Error: No address space found with magic "MAGIC_FMT"\n", space_magic); goto next; } v.address = address_from_human_readable(space, addr_str); if(v.address == NULL) { fprintf(stderr, "Error: Failed to parse address \"%s\"\n", addr_str); goto next; } rc = measurement_graph_add_node(graph, &v, NULL, &n); if(rc == 0 || rc == 1) { printf(ID_FMT"\n", n); } else { fprintf(stderr, "Error adding node\n"); } free_address(v.address); } else if(strcmp(cmd, "add-edge") == 0) { node_id_t src, dst; char *label = NULL; int offset; int rc; edge_id_t e; if(graph == NULL) { fprintf(stderr, "Error: must create a graph with 'new' first\n"); goto next; } if(sscanf(args, " "ID_FMT" "ID_FMT" %n", &src, &dst, &offset) != 2) { fprintf(stderr, "Error: add-edge [