1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2025 Didi Technology Co., Tao Chen */ 3 4 #ifndef _GNU_SOURCE 5 #define _GNU_SOURCE 6 #endif 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <stdbool.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <mntent.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 18 #include "json_writer.h" 19 #include "main.h" 20 21 #define MOUNTS_FILE "/proc/mounts" 22 23 static struct { 24 const char *header; 25 const char *key; 26 } sets[] = { 27 {"allowed_cmds", "delegate_cmds"}, 28 {"allowed_maps", "delegate_maps"}, 29 {"allowed_progs", "delegate_progs"}, 30 {"allowed_attachs", "delegate_attachs"}, 31 }; 32 33 static bool has_delegate_options(const char *mnt_ops) 34 { 35 return strstr(mnt_ops, "delegate_cmds") || 36 strstr(mnt_ops, "delegate_maps") || 37 strstr(mnt_ops, "delegate_progs") || 38 strstr(mnt_ops, "delegate_attachs"); 39 } 40 41 static char *get_delegate_value(char *opts, const char *key) 42 { 43 char *token, *rest, *ret = NULL; 44 45 if (!opts) 46 return NULL; 47 48 for (token = strtok_r(opts, ",", &rest); token; 49 token = strtok_r(NULL, ",", &rest)) { 50 if (strncmp(token, key, strlen(key)) == 0 && 51 token[strlen(key)] == '=') { 52 ret = token + strlen(key) + 1; 53 break; 54 } 55 } 56 57 return ret; 58 } 59 60 static void print_items_per_line(char *input, int items_per_line) 61 { 62 char *str, *rest; 63 int cnt = 0; 64 65 if (!input) 66 return; 67 68 for (str = strtok_r(input, ":", &rest); str; 69 str = strtok_r(NULL, ":", &rest)) { 70 if (cnt % items_per_line == 0) 71 printf("\n\t "); 72 73 printf("%-20s", str); 74 cnt++; 75 } 76 } 77 78 #define ITEMS_PER_LINE 4 79 static void show_token_info_plain(struct mntent *mntent) 80 { 81 size_t i; 82 83 printf("token_info %s", mntent->mnt_dir); 84 85 for (i = 0; i < ARRAY_SIZE(sets); i++) { 86 char *opts, *value; 87 88 printf("\n\t%s:", sets[i].header); 89 opts = strdup(mntent->mnt_opts); 90 value = get_delegate_value(opts, sets[i].key); 91 print_items_per_line(value, ITEMS_PER_LINE); 92 free(opts); 93 } 94 95 printf("\n"); 96 } 97 98 static void split_json_array_str(char *input) 99 { 100 char *str, *rest; 101 102 if (!input) { 103 jsonw_start_array(json_wtr); 104 jsonw_end_array(json_wtr); 105 return; 106 } 107 108 jsonw_start_array(json_wtr); 109 for (str = strtok_r(input, ":", &rest); str; 110 str = strtok_r(NULL, ":", &rest)) { 111 jsonw_string(json_wtr, str); 112 } 113 jsonw_end_array(json_wtr); 114 } 115 116 static void show_token_info_json(struct mntent *mntent) 117 { 118 size_t i; 119 120 jsonw_start_object(json_wtr); 121 jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); 122 123 for (i = 0; i < ARRAY_SIZE(sets); i++) { 124 char *opts, *value; 125 126 jsonw_name(json_wtr, sets[i].header); 127 opts = strdup(mntent->mnt_opts); 128 value = get_delegate_value(opts, sets[i].key); 129 split_json_array_str(value); 130 free(opts); 131 } 132 133 jsonw_end_object(json_wtr); 134 } 135 136 static int __show_token_info(struct mntent *mntent) 137 { 138 if (json_output) 139 show_token_info_json(mntent); 140 else 141 show_token_info_plain(mntent); 142 143 return 0; 144 } 145 146 static int show_token_info(void) 147 { 148 FILE *fp; 149 struct mntent *ent; 150 151 fp = setmntent(MOUNTS_FILE, "r"); 152 if (!fp) { 153 p_err("Failed to open: %s", MOUNTS_FILE); 154 return -1; 155 } 156 157 if (json_output) 158 jsonw_start_array(json_wtr); 159 160 while ((ent = getmntent(fp)) != NULL) { 161 if (strncmp(ent->mnt_type, "bpf", 3) == 0) { 162 if (has_delegate_options(ent->mnt_opts)) 163 __show_token_info(ent); 164 } 165 } 166 167 if (json_output) 168 jsonw_end_array(json_wtr); 169 170 endmntent(fp); 171 172 return 0; 173 } 174 175 static int do_show(int argc, char **argv) 176 { 177 if (argc) 178 return BAD_ARG(); 179 180 return show_token_info(); 181 } 182 183 static int do_help(int argc, char **argv) 184 { 185 if (json_output) { 186 jsonw_null(json_wtr); 187 return 0; 188 } 189 190 fprintf(stderr, 191 "Usage: %1$s %2$s { show | list }\n" 192 " %1$s %2$s help\n" 193 " " HELP_SPEC_OPTIONS " }\n" 194 "\n" 195 "", 196 bin_name, argv[-2]); 197 return 0; 198 } 199 200 static const struct cmd cmds[] = { 201 { "show", do_show }, 202 { "list", do_show }, 203 { "help", do_help }, 204 { 0 } 205 }; 206 207 int do_token(int argc, char **argv) 208 { 209 return cmd_select(cmds, argc, argv, do_help); 210 } 211