| // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| /* Copyright (C) 2025 Didi Technology Co., Tao Chen */ | |
| #ifndef _GNU_SOURCE | |
| #define _GNU_SOURCE | |
| #endif | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <stdbool.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <mntent.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include "json_writer.h" | |
| #include "main.h" | |
| #define MOUNTS_FILE "/proc/mounts" | |
| static struct { | |
| const char *header; | |
| const char *key; | |
| } sets[] = { | |
| {"allowed_cmds", "delegate_cmds"}, | |
| {"allowed_maps", "delegate_maps"}, | |
| {"allowed_progs", "delegate_progs"}, | |
| {"allowed_attachs", "delegate_attachs"}, | |
| }; | |
| static bool has_delegate_options(const char *mnt_ops) | |
| { | |
| return strstr(mnt_ops, "delegate_cmds") || | |
| strstr(mnt_ops, "delegate_maps") || | |
| strstr(mnt_ops, "delegate_progs") || | |
| strstr(mnt_ops, "delegate_attachs"); | |
| } | |
| static char *get_delegate_value(char *opts, const char *key) | |
| { | |
| char *token, *rest, *ret = NULL; | |
| if (!opts) | |
| return NULL; | |
| for (token = strtok_r(opts, ",", &rest); token; | |
| token = strtok_r(NULL, ",", &rest)) { | |
| if (strncmp(token, key, strlen(key)) == 0 && | |
| token[strlen(key)] == '=') { | |
| ret = token + strlen(key) + 1; | |
| break; | |
| } | |
| } | |
| return ret; | |
| } | |
| static void print_items_per_line(char *input, int items_per_line) | |
| { | |
| char *str, *rest; | |
| int cnt = 0; | |
| if (!input) | |
| return; | |
| for (str = strtok_r(input, ":", &rest); str; | |
| str = strtok_r(NULL, ":", &rest)) { | |
| if (cnt % items_per_line == 0) | |
| printf("\n\t "); | |
| printf("%-20s", str); | |
| cnt++; | |
| } | |
| } | |
| #define ITEMS_PER_LINE 4 | |
| static void show_token_info_plain(struct mntent *mntent) | |
| { | |
| size_t i; | |
| printf("token_info %s", mntent->mnt_dir); | |
| for (i = 0; i < ARRAY_SIZE(sets); i++) { | |
| char *opts, *value; | |
| printf("\n\t%s:", sets[i].header); | |
| opts = strdup(mntent->mnt_opts); | |
| value = get_delegate_value(opts, sets[i].key); | |
| print_items_per_line(value, ITEMS_PER_LINE); | |
| free(opts); | |
| } | |
| printf("\n"); | |
| } | |
| static void split_json_array_str(char *input) | |
| { | |
| char *str, *rest; | |
| if (!input) { | |
| jsonw_start_array(json_wtr); | |
| jsonw_end_array(json_wtr); | |
| return; | |
| } | |
| jsonw_start_array(json_wtr); | |
| for (str = strtok_r(input, ":", &rest); str; | |
| str = strtok_r(NULL, ":", &rest)) { | |
| jsonw_string(json_wtr, str); | |
| } | |
| jsonw_end_array(json_wtr); | |
| } | |
| static void show_token_info_json(struct mntent *mntent) | |
| { | |
| size_t i; | |
| jsonw_start_object(json_wtr); | |
| jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); | |
| for (i = 0; i < ARRAY_SIZE(sets); i++) { | |
| char *opts, *value; | |
| jsonw_name(json_wtr, sets[i].header); | |
| opts = strdup(mntent->mnt_opts); | |
| value = get_delegate_value(opts, sets[i].key); | |
| split_json_array_str(value); | |
| free(opts); | |
| } | |
| jsonw_end_object(json_wtr); | |
| } | |
| static int __show_token_info(struct mntent *mntent) | |
| { | |
| if (json_output) | |
| show_token_info_json(mntent); | |
| else | |
| show_token_info_plain(mntent); | |
| return 0; | |
| } | |
| static int show_token_info(void) | |
| { | |
| FILE *fp; | |
| struct mntent *ent; | |
| fp = setmntent(MOUNTS_FILE, "r"); | |
| if (!fp) { | |
| p_err("Failed to open: %s", MOUNTS_FILE); | |
| return -1; | |
| } | |
| if (json_output) | |
| jsonw_start_array(json_wtr); | |
| while ((ent = getmntent(fp)) != NULL) { | |
| if (strncmp(ent->mnt_type, "bpf", 3) == 0) { | |
| if (has_delegate_options(ent->mnt_opts)) | |
| __show_token_info(ent); | |
| } | |
| } | |
| if (json_output) | |
| jsonw_end_array(json_wtr); | |
| endmntent(fp); | |
| return 0; | |
| } | |
| static int do_show(int argc, char **argv) | |
| { | |
| if (argc) | |
| return BAD_ARG(); | |
| return show_token_info(); | |
| } | |
| static int do_help(int argc, char **argv) | |
| { | |
| if (json_output) { | |
| jsonw_null(json_wtr); | |
| return 0; | |
| } | |
| fprintf(stderr, | |
| "Usage: %1$s %2$s { show | list }\n" | |
| " %1$s %2$s help\n" | |
| " " HELP_SPEC_OPTIONS " }\n" | |
| "\n" | |
| "", | |
| bin_name, argv[-2]); | |
| return 0; | |
| } | |
| static const struct cmd cmds[] = { | |
| { "show", do_show }, | |
| { "list", do_show }, | |
| { "help", do_help }, | |
| { 0 } | |
| }; | |
| int do_token(int argc, char **argv) | |
| { | |
| return cmd_select(cmds, argc, argv, do_help); | |
| } |