summaryrefslogtreecommitdiff
path: root/minecctl/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'minecctl/misc.c')
-rw-r--r--minecctl/misc.c215
1 files changed, 215 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <termios.h>
+
+#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);
+}
+