xref: /linux/tools/bpf/bpftool/token.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
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