#include #include #include #include #include #include #include "shared/utils.h" #include "misc.h" #include "minecctl.h" /* 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; enable_colors(); } char **strv_copy(char *const *strv) { size_t len = 1; char **rv; char **to; for (char *const *str = strv; *str; str++) len++; rv = zmalloc(len * sizeof(char *)); to = rv; for (char *const *str = strv; *str; str++) *(to++) = xstrdup(*str); return rv; } char **strv_from_strs(const char *first, ...) { size_t len = 1; va_list ap; char **rv, **to; if (first) { va_start(ap, first); while (va_arg(ap, const char *)) len++; va_end(ap); } rv = zmalloc(len * sizeof(char *)); to = rv; *(to++) = first ? xstrdup(first) : NULL; if (first) { const char *str; va_start(ap, first); while ((str = va_arg(ap, const char *))) *(to++) = xstrdup(str); va_end(ap); *to = NULL; } return rv; } char *strv_join(char *const *strv) { size_t len = 0; char *rv, *to; for (char *const *str = strv; *str; str++) len += strlen(*str) + 1; if (len == 0) return NULL; rv = zmalloc(len); to = rv; for (char *const *str = strv; *str; str++) { if (str != strv) *(to++) = ' '; to = stpcpy(to, *str); } return rv; } void strv_free(char **strv) { if (!strv) return; for (char **str = strv; *str; str++) xfree(*str); xfree(strv); } int connect_any(struct list_head *addrs, bool may_fail) { struct saddr *saddr; bool connected = false; int sfd; /* FIXME: check callers and coordinate debug msg */ if (list_empty(addrs)) { if (may_fail) return -1; else die("No address to connect to"); } list_for_each_entry(saddr, addrs, list) { verbose("Attempting connection to %s", saddr->addrstr); sfd = socket(saddr->st.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->st, 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; } 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; } void free_password(char **password) { if (!password || !*password) return; explicit_bzero(*password, strlen(*password)); xfree(*password); *password = NULL; } void __debug(_unused_ enum debug_lvl lvl, const char *fmt, ...) { va_list ap; const char *color = NULL; if (lvl & DBG_ERROR) color = ansi_red; else if (!(lvl & (DBG_INFO | DBG_VERBOSE))) color = ansi_grey; if (color) fprintf(stderr, "%s", color); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if (color) fprintf(stderr, "%s", 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); }