|  | #include <sys/socket.h> | 
|  | #include <sys/un.h> | 
|  | #include <unistd.h> | 
|  | #include "syncrw.h" | 
|  | #include <getopt.h> | 
|  | #include <fcntl.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <errno.h> | 
|  | //#include <sys/stat.h> | 
|  | #include "packet.h" | 
|  |  | 
|  | #define _(S) (S) | 
|  |  | 
|  | static void print_usage(const char *); | 
|  |  | 
|  | //static struct sockaddr_un sockaddr = { .sun_family = AF_UNIX, .sun_path = "mcipm" }; | 
|  | static int fd = -1; | 
|  |  | 
|  | static int entitystat_command(int argc, char **argv) { | 
|  | static const struct option long_options[] = { | 
|  | { "all", 0, NULL, 'A' }, | 
|  | { "entity-id", 1, NULL, 'i' }, | 
|  | { "sort", 1, NULL, 'k' }, | 
|  | { "format", 1, NULL, 'o' }, | 
|  | { "entity-type", 1, NULL, 't' }, | 
|  | { "world", 1, NULL, 'W' }, | 
|  | { NULL, 0, NULL, 0 } | 
|  | }; | 
|  | unsigned char *selectors = NULL, *selectors_end = NULL; | 
|  | unsigned int selector_count = 0; | 
|  | int select_all = 0; | 
|  | optind = 0; | 
|  | while(1) { | 
|  | int c = getopt_long(argc, argv, "Ai:k:o:t:W:w", long_options, NULL); | 
|  | if(c == -1) break; | 
|  | switch(c) { | 
|  | case 'A': | 
|  | select_all = 1; | 
|  | break; | 
|  | case 'W': | 
|  | if(!select_all) { | 
|  | size_t len = strlen(optarg); | 
|  | unsigned char *p = realloc(selectors, (selectors_end - selectors) + 1 + 1 + len); | 
|  | if(!p) { | 
|  | fputs("Out of memory\n", stderr); | 
|  | return 1; | 
|  | } | 
|  | selectors_end = p + (selectors_end - selectors); | 
|  | selectors = p; | 
|  | *selectors_end++ = MCIPM_GET_ENTITIES_SELECTOR_WORLD; | 
|  | *selectors_end++ = len; | 
|  | memcpy(selectors_end, optarg, len); | 
|  | selectors_end += len; | 
|  | selector_count++; | 
|  | } | 
|  | break; | 
|  | case '?': | 
|  | print_usage(argv[0]); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | if(!selectors && !select_all) { | 
|  | fprintf(stderr, "%s: you must specify a selector\n", argv[0]); | 
|  | print_usage(argv[0]); | 
|  | return -1; | 
|  | } | 
|  | if(select_all) { | 
|  | free(selectors); | 
|  | selectors = malloc(1); | 
|  | *selectors = MCIPM_GET_ENTITIES_SELECTOR_ALL; | 
|  | selectors_end = selectors + 1; | 
|  | selector_count = 1; | 
|  | } | 
|  | if(send_packet_get_entities(fd, selectors, selectors_end - selectors, selector_count) < 0) { | 
|  | fputs("send_packet_get_entities failed\n", stderr); | 
|  | return 1; | 
|  | } | 
|  | fputs("packet sent\n", stderr); | 
|  | struct mcipm_packet *packet; | 
|  | int e = receive_packet(fd, &packet, 1); | 
|  | if(e) { | 
|  | fprintf(stderr, "receive_packet error %d\n", e); | 
|  | return 1; | 
|  | } | 
|  | if(packet->type != MCIPM_REPLY_ENTITIES) { | 
|  | fprintf(stderr, "expecting reply packet type MCIPM_REPLY_ENTITIES (%hhu), got %hhu", | 
|  | MCIPM_REPLY_ENTITIES, packet->type); | 
|  | return 1; | 
|  | } | 
|  | uint32_t entity_count = *(uint32_t *)packet->data; | 
|  | fprintf(stderr, "entity_count = %u\n", (unsigned int)entity_count); | 
|  | struct entity **entities = malloc(sizeof(struct entity *) * entity_count); | 
|  | if(!entities) { | 
|  | fputs("Out of memory\n", stderr); | 
|  | return 1; | 
|  | } | 
|  | uint32_t i = 0; | 
|  | uint32_t offset = 4; | 
|  | while(i < entity_count) { | 
|  | if(offset >= packet->length - 1) { | 
|  | fprintf(stderr, "entity entry offset (%u) out of packet (length %u)\n", | 
|  | (unsigned int)offset, (unsigned int)packet->length); | 
|  | return 1; | 
|  | } | 
|  | struct entity *entity = (struct entity *)(packet->data + offset); | 
|  | fprintf(stderr, "entity->entry_length = %u\n", (unsigned int)entity->entry_length); | 
|  | offset += entity->entry_length; | 
|  | entities[i++] = entity; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int version_command(int argc, char **argv) { | 
|  | if(send_packet_get_version(fd) < 0) { | 
|  | fputs("send_packet_get_version failed\n", stderr); | 
|  | return 1; | 
|  | } | 
|  | struct mcipm_packet *packet; | 
|  | int e = receive_packet(fd, &packet, 1); | 
|  | if(e) { | 
|  | fprintf(stderr, "receive_packet error %d\n", e); | 
|  | return 1; | 
|  | } | 
|  | if(packet->type != MCIPM_REPLY_VERSION) { | 
|  | fprintf(stderr, "expecting reply packet type MCIPM_REPLY_VERSION (%hhu), got %hhu", | 
|  | MCIPM_REPLY_VERSION, packet->type); | 
|  | return 1; | 
|  | } | 
|  | fwrite(packet->data, packet->length - 1, 1, stdout); | 
|  | putchar('\n'); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct subcommand { | 
|  | const char *name; | 
|  | const char *usage; | 
|  | int (*func)(int, char **); | 
|  | } commands[] = { | 
|  | #define SUBCOMMAND(N,U) { #N, U, N##_command } | 
|  | SUBCOMMAND(entitystat, "[-o <colum>[=<title>|,<colum>]] { -A | -w <world-type> | -t <entity-type> }"), | 
|  | SUBCOMMAND(version, ""), | 
|  | #undef SUBCOMMAND | 
|  | { NULL, NULL, NULL } | 
|  | }; | 
|  |  | 
|  | static void print_commands() { | 
|  | struct subcommand *c = commands; | 
|  | fputs(_("Following subcommands are available:\n"), stderr); | 
|  | while(c->name) { | 
|  | fprintf(stderr, "	%s %s\n", c->name, c->usage); | 
|  | c++; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void print_usage(const char *name) { | 
|  | struct subcommand *c = commands; | 
|  | while(c->name) { | 
|  | if(strcmp(c->name, name) == 0) { | 
|  | fprintf(stderr, _("Usage: %s %s\n"), name, c->usage); | 
|  | return; | 
|  | } | 
|  | c++; | 
|  | } | 
|  | fprintf(stderr, _("Error: cannot find usage for command '%s'"), name); | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) { | 
|  | static const struct option long_options[] = { | 
|  | [0] = { "socket-path", 1, NULL, 'S' }, | 
|  | [1] = { "version", 0, NULL, 0 }, | 
|  | { NULL, 0, NULL, 0 } | 
|  | }; | 
|  | struct sockaddr_un sockaddr = { .sun_family = AF_UNIX, .sun_path = "mcipm" }; | 
|  | while(1) { | 
|  | int c = getopt_long(argc, argv, "+S:", long_options, NULL); | 
|  | if(c == -1) break; | 
|  | switch(c) { | 
|  | case 0: | 
|  | puts("MCIPM 1.0"); | 
|  | return 0; | 
|  | case 'S': | 
|  | if(strlen(optarg) + 1 > sizeof sockaddr.sun_path) { | 
|  | fprintf(stderr, "%s: Specified socket path too long\n", argv[0]); | 
|  | return -1; | 
|  | } | 
|  | strcpy(sockaddr.sun_path, optarg); | 
|  | break; | 
|  | case '?': | 
|  | fprintf(stderr, "Usage: %s [--socket-path <path>] <subcommand> [<options>]\n", argv[0]); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(argc <= optind) { | 
|  | print_commands(); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | fd = socket(AF_UNIX, SOCK_STREAM, 0); | 
|  | if(fd == -1) { | 
|  | perror("socket: AF_UNIX"); | 
|  | return 1; | 
|  | } | 
|  | while(connect(fd, (struct sockaddr *)&sockaddr, sizeof sockaddr) < 0) { | 
|  | if(errno == EINTR) continue; | 
|  | perror("connect"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | struct subcommand *c = commands; | 
|  | while(c->name) { | 
|  | if(strcmp(argv[optind], c->name) == 0) return c->func(argc - optind, argv + optind); | 
|  | c++; | 
|  | } | 
|  | fprintf(stderr, _("Unknown command '%s'\n"), argv[optind]); | 
|  | print_commands(); | 
|  | return -1; | 
|  | } |