// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2009-2019 B.A.T.M.A.N. contributors: * * Marek Lindner * * License-Filename: LICENSES/preferred/GPL-2.0 */ #include #include #include #include #include #include #include "functions.h" #include "main.h" #include "sys.h" #define SYS_LOG_LEVEL "log_level" static struct log_level_data { uint32_t log_level; } log_level_globals; static void log_level_usage(void) { fprintf(stderr, "Usage: batctl [options] loglevel [parameters] [level[ level[ level]]...]\n"); fprintf(stderr, "parameters:\n"); fprintf(stderr, " \t -h print this help\n"); fprintf(stderr, "levels:\n"); fprintf(stderr, " \t none Debug logging is disabled\n"); fprintf(stderr, " \t all Print messages from all below\n"); fprintf(stderr, " \t batman Messages related to routing / flooding / broadcasting\n"); fprintf(stderr, " \t routes Messages related to route added / changed / deleted\n"); fprintf(stderr, " \t tt Messages related to translation table operations\n"); fprintf(stderr, " \t bla Messages related to bridge loop avoidance\n"); fprintf(stderr, " \t dat Messages related to arp snooping and distributed arp table\n"); fprintf(stderr, " \t nc Messages related to network coding\n"); fprintf(stderr, " \t mcast Messages related to multicast\n"); fprintf(stderr, " \t tp Messages related to throughput meter\n"); } static int extract_log_level(struct nl_msg *msg, void *arg) { struct nlattr *attrs[BATADV_ATTR_MAX + 1]; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *ghdr; int *result = arg; if (!genlmsg_valid_hdr(nlh, 0)) return NL_OK; ghdr = nlmsg_data(nlh); if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), batadv_netlink_policy)) { return NL_OK; } if (!attrs[BATADV_ATTR_LOG_LEVEL]) return NL_OK; log_level_globals.log_level = nla_get_u32(attrs[BATADV_ATTR_LOG_LEVEL]); *result = 0; return NL_STOP; } static int get_log_level(struct state *state) { return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, NULL, extract_log_level); } static int set_attrs_log_level(struct nl_msg *msg, void *arg __maybe_unused) { nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, log_level_globals.log_level); return 0; } static int set_log_level(struct state *state) { return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, set_attrs_log_level, NULL); } static int log_level_read_setting(struct state *state, const char *path_buff) { int res; res = get_log_level(state); if (res < 0 && res != -EOPNOTSUPP) return EXIT_FAILURE; if (res >= 0) return EXIT_SUCCESS; res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0); if (res != EXIT_SUCCESS) return res; log_level_globals.log_level = strtol(line_ptr, (char **) NULL, 10); return res; } static int log_level_write_setting(struct state *state, const char *path_buff) { int res; char str[4]; res = set_log_level(state); if (res < 0 && res != -EOPNOTSUPP) return EXIT_FAILURE; if (res >= 0) return EXIT_SUCCESS; snprintf(str, sizeof(str), "%i", log_level_globals.log_level); return write_file(path_buff, SYS_LOG_LEVEL, str, NULL); } static int loglevel(struct state *state, int argc, char **argv) { int optchar, res = EXIT_FAILURE; char *path_buff; int i; log_level_globals.log_level = 0; while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { case 'h': log_level_usage(); return EXIT_SUCCESS; default: log_level_usage(); return EXIT_FAILURE; } } path_buff = malloc(PATH_BUFF_LEN); if (!path_buff) { fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); return EXIT_FAILURE; } snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); if (argc != 1) { check_root_or_die("batctl loglevel"); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "none") == 0) { log_level_globals.log_level = 0; break; } else if (strcmp(argv[i], "all") == 0) { log_level_globals.log_level = 255; break; } else if (strcmp(argv[i], "batman") == 0) log_level_globals.log_level |= BIT(0); else if (strcmp(argv[i], "routes") == 0) log_level_globals.log_level |= BIT(1); else if (strcmp(argv[i], "tt") == 0) log_level_globals.log_level |= BIT(2); else if (strcmp(argv[i], "bla") == 0) log_level_globals.log_level |= BIT(3); else if (strcmp(argv[i], "dat") == 0) log_level_globals.log_level |= BIT(4); else if (strcmp(argv[i], "nc") == 0) log_level_globals.log_level |= BIT(5); else if (strcmp(argv[i], "mcast") == 0) log_level_globals.log_level |= BIT(6); else if (strcmp(argv[i], "tp") == 0) log_level_globals.log_level |= BIT(7); else { log_level_usage(); goto out; } } log_level_write_setting(state, path_buff); goto out; } res = log_level_read_setting(state, path_buff); if (res != EXIT_SUCCESS) goto out; printf("[%c] %s (%s)\n", (!log_level_globals.log_level) ? 'x' : ' ', "all debug output disabled", "none"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(0)) ? 'x' : ' ', "messages related to routing / flooding / broadcasting", "batman"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(1)) ? 'x' : ' ', "messages related to route added / changed / deleted", "routes"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(2)) ? 'x' : ' ', "messages related to translation table operations", "tt"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(3)) ? 'x' : ' ', "messages related to bridge loop avoidance", "bla"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(4)) ? 'x' : ' ', "messages related to arp snooping and distributed arp table", "dat"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(5)) ? 'x' : ' ', "messages related to network coding", "nc"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(6)) ? 'x' : ' ', "messages related to multicast", "mcast"); printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(7)) ? 'x' : ' ', "messages related to throughput meter", "tp"); out: free(path_buff); return res; } COMMAND(SUBCOMMAND, loglevel, "ll", COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "[level] \tdisplay or modify the log level");