From 06a2edfc72a894054ed710d338504242f15d6071 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Fri, 26 Jun 2020 03:23:41 +0200 Subject: Make the server handling in minecctl saner --- minecctl/misc.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 minecctl/misc.c (limited to 'minecctl/misc.c') diff --git a/minecctl/misc.c b/minecctl/misc.c new file mode 100644 index 0000000..13b4377 --- /dev/null +++ b/minecctl/misc.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "minecctl.h" + +bool use_colors = false; + +/* FIXME: Can be shared */ +void +set_use_colors() +{ + int fd; + const char *e; + + if (getenv("NO_COLOR")) + return; + + fd = fileno(stderr); + if (fd < 0) + return; + + if (!isatty(fd)) + return; + + e = getenv("TERM"); + if (!e) + return; + + if (streq(e, "dumb")) + return; + + use_colors = true; +} + +char * +strv_join(char * const *strv) +{ + size_t len = 0; + char *r, *to; + + for (unsigned i = 0; strv[i]; i++) + len += strlen(strv[i]) + 1; + + if (len == 0) + return NULL; + + r = zmalloc(len); + to = r; + + for (unsigned i = 0; strv[i]; i++) { + if (i > 0) + *(to++) = ' '; + to = stpcpy(to, strv[i]); + } + + return r; +} + +char * +ask_password() +{ + struct termios old, new; + char *password = NULL; + size_t len = 0; + ssize_t r; + + if (!isatty(STDIN_FILENO)) + return NULL; + + if (tcgetattr(STDIN_FILENO, &old) < 0) + return NULL; + + new = old; + new.c_lflag &= ~ECHO; + new.c_lflag |= ICANON; + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &new) < 0) + return NULL; + + fprintf(stderr, "Password: "); + r = getline(&password, &len, stdin); + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &old); + + if (r < 0) { + info("Error in getline: %m"); + clearerr(stdin); + free(password); + return NULL; + } + + while (r > 0 && password[r - 1] == '\n') + password[--r] = '\0'; + + return password; +} + +int +connect_any(struct list_head *addrs, bool may_fail) +{ + struct saddr *saddr; + bool connected = false; + int sfd; + + if (list_empty(addrs)) + die("No address to connect to"); + + list_for_each_entry(saddr, addrs, list) { + verbose("Attempting connection to %s", saddr->addrstr); + sfd = socket(saddr->storage.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sfd < 0) + die("socket: %m"); + + socket_set_low_latency(sfd, true, true, true); + + if (connect(sfd, (struct sockaddr *)&saddr->storage, saddr->addrlen) < 0) { + close(sfd); + continue; + } + + connected = true; + break; + } + + if (!connected && may_fail) + return -1; + else if (!connected) + die("Failed to connect to remote host"); + + return sfd; +} + +void +__debug(_unused_ enum debug_lvl lvl, const char *fmt, ...) +{ + va_list ap; + + if (use_colors) { + if (lvl & DBG_ERROR) + fprintf(stderr, ANSI_RED); + else if (!(lvl & (DBG_INFO | DBG_VERBOSE))) + fprintf(stderr, ANSI_GREY); + } + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (use_colors && !(lvl & (DBG_INFO | DBG_VERBOSE))) + fprintf(stderr, ANSI_NORMAL); +} + +_noreturn_ void +__die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + exit(EXIT_FAILURE); +} + +void * +__zmalloc(const char *fn, int line, size_t size) +{ + void *ptr; + + assert_die(!empty_str(fn) && line > 0 && size > 0, "invalid arguments"); + + ptr = calloc(1, size); + if (!ptr) + die("malloc: %m"); + return ptr; +} + +char * +__xstrdup(const char *fn, int line, const char *s) +{ + char *ptr; + + assert_die(!empty_str(fn) && line > 0 && !empty_str(s), "invalid arguments"); + + ptr = strdup(s); + if (!ptr) + die("strdup: %m"); + return ptr; +} + +char * +__xstrndup(const char *fn, int line, const char *s, size_t n) +{ + char *ptr; + + assert_die(!empty_str(fn) && line > 0 && !empty_str(s) && n > 0, "invalid arguments"); + + ptr = strndup(s, n); + if (ptr) + die("strdup: %m"); + return ptr; +} + +void +__xfree(const char *fn, int line, void *ptr) +{ + assert_die(!empty_str(fn) && line > 0, "invalid arguments"); + + free(ptr); +} + -- cgit v1.2.3