12d812311STao Chen // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 22d812311STao Chen /* Copyright (C) 2025 Didi Technology Co., Tao Chen */ 32d812311STao Chen 42d812311STao Chen #ifndef _GNU_SOURCE 52d812311STao Chen #define _GNU_SOURCE 62d812311STao Chen #endif 72d812311STao Chen #include <errno.h> 82d812311STao Chen #include <fcntl.h> 92d812311STao Chen #include <stdbool.h> 102d812311STao Chen #include <stdio.h> 112d812311STao Chen #include <stdlib.h> 122d812311STao Chen #include <string.h> 132d812311STao Chen #include <unistd.h> 142d812311STao Chen #include <mntent.h> 152d812311STao Chen #include <sys/types.h> 162d812311STao Chen #include <sys/stat.h> 172d812311STao Chen 182d812311STao Chen #include "json_writer.h" 192d812311STao Chen #include "main.h" 202d812311STao Chen 212d812311STao Chen #define MOUNTS_FILE "/proc/mounts" 222d812311STao Chen 23*57cb2695STao Chen static struct { 24*57cb2695STao Chen const char *header; 25*57cb2695STao Chen const char *key; 26*57cb2695STao Chen } sets[] = { 27*57cb2695STao Chen {"allowed_cmds", "delegate_cmds"}, 28*57cb2695STao Chen {"allowed_maps", "delegate_maps"}, 29*57cb2695STao Chen {"allowed_progs", "delegate_progs"}, 30*57cb2695STao Chen {"allowed_attachs", "delegate_attachs"}, 31*57cb2695STao Chen }; 32*57cb2695STao Chen 332d812311STao Chen static bool has_delegate_options(const char *mnt_ops) 342d812311STao Chen { 352d812311STao Chen return strstr(mnt_ops, "delegate_cmds") || 362d812311STao Chen strstr(mnt_ops, "delegate_maps") || 372d812311STao Chen strstr(mnt_ops, "delegate_progs") || 382d812311STao Chen strstr(mnt_ops, "delegate_attachs"); 392d812311STao Chen } 402d812311STao Chen 41*57cb2695STao Chen static char *get_delegate_value(char *opts, const char *key) 422d812311STao Chen { 432d812311STao Chen char *token, *rest, *ret = NULL; 442d812311STao Chen 45*57cb2695STao Chen if (!opts) 462d812311STao Chen return NULL; 472d812311STao Chen 48*57cb2695STao Chen for (token = strtok_r(opts, ",", &rest); token; 492d812311STao Chen token = strtok_r(NULL, ",", &rest)) { 502d812311STao Chen if (strncmp(token, key, strlen(key)) == 0 && 512d812311STao Chen token[strlen(key)] == '=') { 522d812311STao Chen ret = token + strlen(key) + 1; 532d812311STao Chen break; 542d812311STao Chen } 552d812311STao Chen } 562d812311STao Chen 572d812311STao Chen return ret; 582d812311STao Chen } 592d812311STao Chen 60*57cb2695STao Chen static void print_items_per_line(char *input, int items_per_line) 612d812311STao Chen { 62*57cb2695STao Chen char *str, *rest; 632d812311STao Chen int cnt = 0; 642d812311STao Chen 652d812311STao Chen if (!input) 662d812311STao Chen return; 672d812311STao Chen 68*57cb2695STao Chen for (str = strtok_r(input, ":", &rest); str; 692d812311STao Chen str = strtok_r(NULL, ":", &rest)) { 702d812311STao Chen if (cnt % items_per_line == 0) 712d812311STao Chen printf("\n\t "); 722d812311STao Chen 732d812311STao Chen printf("%-20s", str); 742d812311STao Chen cnt++; 752d812311STao Chen } 762d812311STao Chen } 772d812311STao Chen 782d812311STao Chen #define ITEMS_PER_LINE 4 792d812311STao Chen static void show_token_info_plain(struct mntent *mntent) 802d812311STao Chen { 81*57cb2695STao Chen size_t i; 822d812311STao Chen 832d812311STao Chen printf("token_info %s", mntent->mnt_dir); 842d812311STao Chen 85*57cb2695STao Chen for (i = 0; i < ARRAY_SIZE(sets); i++) { 86*57cb2695STao Chen char *opts, *value; 872d812311STao Chen 88*57cb2695STao Chen printf("\n\t%s:", sets[i].header); 89*57cb2695STao Chen opts = strdup(mntent->mnt_opts); 90*57cb2695STao Chen value = get_delegate_value(opts, sets[i].key); 912d812311STao Chen print_items_per_line(value, ITEMS_PER_LINE); 92*57cb2695STao Chen free(opts); 93*57cb2695STao Chen } 942d812311STao Chen 952d812311STao Chen printf("\n"); 962d812311STao Chen } 972d812311STao Chen 98*57cb2695STao Chen static void split_json_array_str(char *input) 992d812311STao Chen { 100*57cb2695STao Chen char *str, *rest; 1012d812311STao Chen 1022d812311STao Chen if (!input) { 1032d812311STao Chen jsonw_start_array(json_wtr); 1042d812311STao Chen jsonw_end_array(json_wtr); 1052d812311STao Chen return; 1062d812311STao Chen } 1072d812311STao Chen 1082d812311STao Chen jsonw_start_array(json_wtr); 109*57cb2695STao Chen for (str = strtok_r(input, ":", &rest); str; 1102d812311STao Chen str = strtok_r(NULL, ":", &rest)) { 1112d812311STao Chen jsonw_string(json_wtr, str); 1122d812311STao Chen } 1132d812311STao Chen jsonw_end_array(json_wtr); 1142d812311STao Chen } 1152d812311STao Chen 1162d812311STao Chen static void show_token_info_json(struct mntent *mntent) 1172d812311STao Chen { 118*57cb2695STao Chen size_t i; 1192d812311STao Chen 1202d812311STao Chen jsonw_start_object(json_wtr); 1212d812311STao Chen jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); 1222d812311STao Chen 123*57cb2695STao Chen for (i = 0; i < ARRAY_SIZE(sets); i++) { 124*57cb2695STao Chen char *opts, *value; 1252d812311STao Chen 126*57cb2695STao Chen jsonw_name(json_wtr, sets[i].header); 127*57cb2695STao Chen opts = strdup(mntent->mnt_opts); 128*57cb2695STao Chen value = get_delegate_value(opts, sets[i].key); 1292d812311STao Chen split_json_array_str(value); 130*57cb2695STao Chen free(opts); 131*57cb2695STao Chen } 1322d812311STao Chen 1332d812311STao Chen jsonw_end_object(json_wtr); 1342d812311STao Chen } 1352d812311STao Chen 1362d812311STao Chen static int __show_token_info(struct mntent *mntent) 1372d812311STao Chen { 1382d812311STao Chen if (json_output) 1392d812311STao Chen show_token_info_json(mntent); 1402d812311STao Chen else 1412d812311STao Chen show_token_info_plain(mntent); 1422d812311STao Chen 1432d812311STao Chen return 0; 1442d812311STao Chen } 1452d812311STao Chen 1462d812311STao Chen static int show_token_info(void) 1472d812311STao Chen { 1482d812311STao Chen FILE *fp; 1492d812311STao Chen struct mntent *ent; 1502d812311STao Chen 1512d812311STao Chen fp = setmntent(MOUNTS_FILE, "r"); 1522d812311STao Chen if (!fp) { 1532d812311STao Chen p_err("Failed to open: %s", MOUNTS_FILE); 1542d812311STao Chen return -1; 1552d812311STao Chen } 1562d812311STao Chen 1572d812311STao Chen if (json_output) 1582d812311STao Chen jsonw_start_array(json_wtr); 1592d812311STao Chen 1602d812311STao Chen while ((ent = getmntent(fp)) != NULL) { 1612d812311STao Chen if (strncmp(ent->mnt_type, "bpf", 3) == 0) { 1622d812311STao Chen if (has_delegate_options(ent->mnt_opts)) 1632d812311STao Chen __show_token_info(ent); 1642d812311STao Chen } 1652d812311STao Chen } 1662d812311STao Chen 1672d812311STao Chen if (json_output) 1682d812311STao Chen jsonw_end_array(json_wtr); 1692d812311STao Chen 1702d812311STao Chen endmntent(fp); 1712d812311STao Chen 1722d812311STao Chen return 0; 1732d812311STao Chen } 1742d812311STao Chen 1752d812311STao Chen static int do_show(int argc, char **argv) 1762d812311STao Chen { 1772d812311STao Chen if (argc) 1782d812311STao Chen return BAD_ARG(); 1792d812311STao Chen 1802d812311STao Chen return show_token_info(); 1812d812311STao Chen } 1822d812311STao Chen 1832d812311STao Chen static int do_help(int argc, char **argv) 1842d812311STao Chen { 1852d812311STao Chen if (json_output) { 1862d812311STao Chen jsonw_null(json_wtr); 1872d812311STao Chen return 0; 1882d812311STao Chen } 1892d812311STao Chen 1902d812311STao Chen fprintf(stderr, 1912d812311STao Chen "Usage: %1$s %2$s { show | list }\n" 1922d812311STao Chen " %1$s %2$s help\n" 193bce5749bSTao Chen " " HELP_SPEC_OPTIONS " }\n" 1942d812311STao Chen "\n" 1952d812311STao Chen "", 1962d812311STao Chen bin_name, argv[-2]); 1972d812311STao Chen return 0; 1982d812311STao Chen } 1992d812311STao Chen 2002d812311STao Chen static const struct cmd cmds[] = { 2012d812311STao Chen { "show", do_show }, 2022d812311STao Chen { "list", do_show }, 2032d812311STao Chen { "help", do_help }, 2042d812311STao Chen { 0 } 2052d812311STao Chen }; 2062d812311STao Chen 2072d812311STao Chen int do_token(int argc, char **argv) 2082d812311STao Chen { 2092d812311STao Chen return cmd_select(cmds, argc, argv, do_help); 2102d812311STao Chen } 211