diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0a0f4..33e12b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,16 @@ ### Added * environment variable substitution in config files ([#96][96]). +* Log output now respects the [`NO_COLOR`](http://no-color.org/) + environment variable. +* network: `type` tag ([#380][380]). +* network: `type` and `kind` tags ([#380][380]). +* tags: `b` tag formatter; divides the tag's decimal value with `8` + ([#392][392]). [96]: https://codeberg.org/dnkl/yambar/issues/96 +[380]: https://codeberg.org/dnkl/yambar/issues/380 +[392]: https://codeberg.org/dnkl/yambar/issues/392 ### Changed @@ -34,6 +42,8 @@ * network: fix missing break in switch statement ([#377][377]). * i3/sway: crash when output is turned off an on ([#300][300]). +* mpd: yambar never attempting to reconnect after MPD closed the + connection (for example, when MPD is restarted). [377]: https://codeberg.org/dnkl/yambar/issues/377 [300]: https://codeberg.org/dnkl/yambar/issues/300 diff --git a/README.md b/README.md index 2887f53..48566dc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Yambar -[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg)](https://repology.org/project/yambar/versions) +[![Packaging status](https://repology.org/badge/vertical-allrepos/yambar.svg?columns=4)](https://repology.org/project/yambar/versions) ## Index diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index cdc5530..afbbae3 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -21,6 +21,16 @@ address per network interface. | name : string : Network interface name +| type +: string +: Interface type (*ether*, *wlan*, *loopback*, or *ARPHRD_NNN*, where + *N* is a number). +| kind +: string +: Interface kind. Empty for non-virtual interfaces. For virtual + interfaces, this value is taken from the _IFLA\_INFO\_KIND_ netlink + attribute. Examples of valid values are *bond*, *bridge*, *gre*, *tun* + and *veth*. | index : int : Network interface index @@ -91,17 +101,23 @@ address per network interface. # EXAMPLES +Display all Ethernet (including WLAN) devices. This excludes loopback, +bridges etc. + ``` bar: left: - network: content: map: - default: - string: {text: "{name}: {state} ({ipv4})"} conditions: - ipv4 == "": - string: {text: "{name}: {state}"} + type == ether || type == wlan: + map: + default: + string: {text: "{name}: {state} ({ipv4})"} + conditions: + ipv4 == "": + string: {text: "{name}: {state}"} ``` # SEE ALSO diff --git a/doc/yambar-tags.5.scd b/doc/yambar-tags.5.scd index b778154..adda208 100644 --- a/doc/yambar-tags.5.scd +++ b/doc/yambar-tags.5.scd @@ -86,11 +86,16 @@ be used. : format : Range tags : Renders a range tag's value as a percentage value +| b +: format +: All tag types +: Renders a tag's value (in decimal) divided by 8. Note: no unit + suffix is appended | kb, mb, gb : format : All tag types : Renders a tag's value (in decimal) divided by 1000, 1000^2 or - 1000^3. Note: no unit suffix is appended) + 1000^3. Note: no unit suffix is appended | kib, mib, gib : format : All tag types diff --git a/log.c b/log.c index 7ba4193..ba4ebd9 100644 --- a/log.c +++ b/log.c @@ -39,9 +39,15 @@ log_init(enum log_colorize _colorize, bool _do_syslog, enum log_facility syslog_ [LOG_FACILITY_DAEMON] = LOG_DAEMON, }; - colorize = _colorize == LOG_COLORIZE_NEVER ? false - : _colorize == LOG_COLORIZE_ALWAYS ? true - : isatty(STDERR_FILENO); + /* Don't use colors if NO_COLOR is defined and not empty */ + const char *no_color_str = getenv("NO_COLOR"); + const bool no_color = no_color_str != NULL && no_color_str[0] != '\0'; + + colorize = _colorize == LOG_COLORIZE_NEVER + ? false + : _colorize == LOG_COLORIZE_ALWAYS + ? true + : !no_color && isatty(STDERR_FILENO); do_syslog = _do_syslog; log_level = _log_level; diff --git a/meson.build b/meson.build index 19488e7..84ab374 100644 --- a/meson.build +++ b/meson.build @@ -12,7 +12,9 @@ plugs_as_libs = get_option('core-plugins-as-shared-libraries') cc = meson.get_compiler('c') -if cc.has_function('memfd_create') +if cc.has_function('memfd_create', + args: ['-D_GNU_SOURCE=200809L'], + prefix: '#include ') add_project_arguments('-DMEMFD_CREATE', language: 'c') endif diff --git a/modules/mpd.c b/modules/mpd.c index 22c0e6b..63da818 100644 --- a/modules/mpd.c +++ b/modules/mpd.c @@ -437,7 +437,7 @@ run(struct module *mod) */ while (!aborted) { struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; - int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 10 * 1000); + int res = poll(fds, sizeof(fds) / sizeof(fds[0]), 2 * 1000); if (res < 0) { if (errno == EINTR) @@ -448,10 +448,16 @@ run(struct module *mod) break; } - if (res == 1) { + if (res == 0) { + ret = 0; + break; + } + + else if (res == 1) { assert(fds[0].revents & POLLIN); aborted = true; } + } } diff --git a/modules/network.c b/modules/network.c index c2f6ec3..1b2ceba 100644 --- a/modules/network.c +++ b/modules/network.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,7 @@ #include #define LOG_MODULE "network" -#define LOG_ENABLE_DBG 0 +#define LOG_ENABLE_DBG 1 #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" @@ -52,6 +53,8 @@ struct af_addr { struct iface { char *name; + char *type; /* ARPHRD_NNN */ + char *kind; /* IFLA_LINKINFO::IFLA_INFO_KIND */ uint32_t get_stats_seq_nr; @@ -104,6 +107,8 @@ free_iface(struct iface iface) { tll_free(iface.addrs); free(iface.ssid); + free(iface.kind); + free(iface.type); free(iface.name); } @@ -207,6 +212,8 @@ content(struct module *mod) struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "name", iface->name), + tag_new_string(mod, "type", iface->type), + tag_new_string(mod, "kind", iface->kind), tag_new_int(mod, "index", iface->index), tag_new_bool(mod, "carrier", iface->carrier), tag_new_string(mod, "state", state), @@ -221,7 +228,7 @@ content(struct module *mod) tag_new_float(mod, "dl-speed", iface->dl_speed), tag_new_float(mod, "ul-speed", iface->ul_speed), }, - .count = 14, + .count = 16, }; exposables[idx++] = m->label->instantiate(m->label, &tags); tag_set_destroy(&tags); @@ -549,6 +556,79 @@ send_nl80211_get_scan(struct private *m) return true; } +static bool +foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, + size_t len, void *ctx), + void *ctx) +{ + const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; + const uint8_t *end = (const uint8_t *)genl + len; + + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { + uint16_t type = attr->nla_type & NLA_TYPE_MASK; + bool nested = (attr->nla_type & NLA_F_NESTED) != 0; + ; + const void *payload = raw + NLA_HDRLEN; + + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) + return false; + } + + return true; +} + +static bool +foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, + bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, + const void *payload, size_t len, void *ctx), + void *ctx) +{ + const uint8_t *raw = parent_payload; + const uint8_t *end = parent_payload + len; + + for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; + raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { + uint16_t type = attr->nla_type & NLA_TYPE_MASK; + bool nested = (attr->nla_type & NLA_F_NESTED) != 0; + const void *payload = raw + NLA_HDRLEN; + + if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) + return false; + } + + return true; +} + +static bool +parse_linkinfo(struct module *mod, struct iface *iface, uint16_t type, + bool nested, const void *payload, size_t len, void *_void) +{ + switch (type) { + case IFLA_INFO_KIND: { + const char *kind = payload; + free(iface->kind); + iface->kind = strndup(kind, len); + + LOG_DBG("%s: IFLA_INFO_KIND: %s", iface->name, iface->kind); + break; + } + + case IFLA_INFO_DATA: + //LOG_DBG("%s: IFLA_INFO_DATA", iface->name); + break; + + default: + LOG_WARN("unrecognized IFLA_LINKINFO attribute: " + "type=%hu, nested=%d, len=%zu", + type, nested, len); + break; + } + + return true; +} + static void handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size_t len) { @@ -581,9 +661,31 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size } if (iface == NULL) { + char *type = NULL; + + switch (msg->ifi_type) { + case ARPHRD_ETHER: + type = strdup("ether"); + break; + + case ARPHRD_LOOPBACK: + type = strdup("loopback"); + break; + + case ARPHRD_IEEE80211: + type = strdup("wlan"); + break; + + default: + if (asprintf(&type, "ARPHRD_%hu", msg->ifi_type) < 0) + type = strdup("unknown"); + break; + } + mtx_lock(&mod->lock); tll_push_back(m->ifaces, ((struct iface){ .index = msg->ifi_index, + .type = type, .state = IF_OPER_DOWN, .addrs = tll_init(), })); @@ -596,9 +698,10 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size case IFLA_IFNAME: mtx_lock(&mod->lock); iface->name = strdup((const char *)RTA_DATA(attr)); - LOG_DBG("%s: index=%d", iface->name, iface->index); + LOG_DBG("%s: index=%d, type=%s", iface->name, iface->index, iface->type); mtx_unlock(&mod->lock); break; + case IFLA_OPERSTATE: { uint8_t operstate = *(const uint8_t *)RTA_DATA(attr); if (iface->state == operstate) @@ -633,7 +736,8 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size if (memcmp(iface->mac, mac, sizeof(iface->mac)) == 0) break; - LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", iface->name, mac[0], mac[1], mac[2], mac[3], + LOG_DBG("%s: IFLA_ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x", + iface->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mtx_lock(&mod->lock); @@ -641,6 +745,13 @@ handle_link(struct module *mod, uint16_t type, const struct ifinfomsg *msg, size mtx_unlock(&mod->lock); break; } + + case IFLA_LINKINFO: { + foreach_nlattr_nested( + mod, iface, RTA_DATA(attr), RTA_PAYLOAD(attr), + &parse_linkinfo, NULL); + break; + } } } @@ -723,51 +834,6 @@ handle_address(struct module *mod, uint16_t type, const struct ifaddrmsg *msg, s mod->bar->refresh(mod->bar); } -static bool -foreach_nlattr(struct module *mod, struct iface *iface, const struct genlmsghdr *genl, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, const void *payload, - size_t len, void *ctx), - void *ctx) -{ - const uint8_t *raw = (const uint8_t *)genl + GENL_HDRLEN; - const uint8_t *end = (const uint8_t *)genl + len; - - for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { - uint16_t type = attr->nla_type & NLA_TYPE_MASK; - bool nested = (attr->nla_type & NLA_F_NESTED) != 0; - ; - const void *payload = raw + NLA_HDRLEN; - - if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) - return false; - } - - return true; -} - -static bool -foreach_nlattr_nested(struct module *mod, struct iface *iface, const void *parent_payload, size_t len, - bool (*cb)(struct module *mod, struct iface *iface, uint16_t type, bool nested, - const void *payload, size_t len, void *ctx), - void *ctx) -{ - const uint8_t *raw = parent_payload; - const uint8_t *end = parent_payload + len; - - for (const struct nlattr *attr = (const struct nlattr *)raw; raw < end; - raw += NLA_ALIGN(attr->nla_len), attr = (const struct nlattr *)raw) { - uint16_t type = attr->nla_type & NLA_TYPE_MASK; - bool nested = (attr->nla_type & NLA_F_NESTED) != 0; - const void *payload = raw + NLA_HDRLEN; - - if (!cb(mod, iface, type, nested, payload, attr->nla_len - NLA_HDRLEN, ctx)) - return false; - } - - return true; -} - struct mcast_group { uint32_t id; const char *name; @@ -1304,6 +1370,8 @@ parse_genl_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) continue; LOG_DBG("%s: got interface information", iface->name); + free(iface->type); + iface->type = strdup("wlan"); foreach_nlattr(mod, iface, genl, msg_size, &handle_nl80211_new_interface, NULL); break; diff --git a/tag.c b/tag.c index e95b1c7..438af64 100644 --- a/tag.c +++ b/tag.c @@ -510,6 +510,7 @@ tags_expand_template(const char *template, const struct tag_set *tags) FMT_HEX, FMT_OCT, FMT_PERCENT, + FMT_BYTE, FMT_KBYTE, FMT_MBYTE, FMT_GBYTE, @@ -541,6 +542,8 @@ tags_expand_template(const char *template, const struct tag_set *tags) format = FMT_OCT; else if (strcmp(tag_args[i], "%") == 0) format = FMT_PERCENT; + else if (strcmp(tag_args[i], "b") == 0) + format = FMT_BYTE; else if (strcmp(tag_args[i], "kb") == 0) format = FMT_KBYTE; else if (strcmp(tag_args[i], "mb") == 0) @@ -634,19 +637,29 @@ tags_expand_template(const char *template, const struct tag_set *tags) break; } + case FMT_BYTE: case FMT_KBYTE: case FMT_MBYTE: case FMT_GBYTE: case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = format == FMT_KBYTE ? 1000 - : format == FMT_MBYTE ? 1000 * 1000 - : format == FMT_GBYTE ? 1000 * 1000 * 1000 - : format == FMT_KIBYTE ? 1024 - : format == FMT_MIBYTE ? 1024 * 1024 - : format == FMT_GIBYTE ? 1024 * 1024 * 1024 - : 1; + const long divider = + format == FMT_BYTE + ? 8 + : format == FMT_KBYTE + ? 1000 + : format == FMT_MBYTE + ? 1000 * 1000 + : format == FMT_GBYTE + ? 1000 * 1000 * 1000 + : format == FMT_KIBYTE + ? 1024 + : format == FMT_MIBYTE + ? 1024 * 1024 + : format == FMT_GIBYTE + ? 1024 * 1024 * 1024 + : 1; char str[24]; if (tag->type(tag) == TAG_TYPE_FLOAT) { @@ -684,19 +697,29 @@ tags_expand_template(const char *template, const struct tag_set *tags) fmt = zero_pad ? "%0*lu" : "%*lu"; break; + case FMT_BYTE: case FMT_KBYTE: case FMT_MBYTE: case FMT_GBYTE: case FMT_KIBYTE: case FMT_MIBYTE: case FMT_GIBYTE: { - const long divider = format == FMT_KBYTE ? 1024 - : format == FMT_MBYTE ? 1024 * 1024 - : format == FMT_GBYTE ? 1024 * 1024 * 1024 - : format == FMT_KIBYTE ? 1000 - : format == FMT_MIBYTE ? 1000 * 1000 - : format == FMT_GIBYTE ? 1000 * 1000 * 1000 - : 1; + const long divider = + format == FMT_BYTE + ? 8 + : format == FMT_KBYTE + ? 1024 + : format == FMT_MBYTE + ? 1024 * 1024 + : format == FMT_GBYTE + ? 1024 * 1024 * 1024 + : format == FMT_KIBYTE + ? 1000 + : format == FMT_MIBYTE + ? 1000 * 1000 + : format == FMT_GIBYTE + ? 1000 * 1000 * 1000 + : 1; value /= divider; fmt = zero_pad ? "%0*lu" : "%*lu"; break;