Line data Source code
1 : #define _GNU_SOURCE
2 : #include "fddev.h"
3 :
4 : #include "../shared/commands/configure/configure.h"
5 : #include "../shared/fd_file_util.h"
6 :
7 : #include <unistd.h>
8 : #include <stdlib.h>
9 : #include <stdio.h>
10 : #include <sys/types.h>
11 : #include <sys/stat.h>
12 :
13 : extern configure_stage_t fd_cfg_stage_kill;
14 : extern configure_stage_t fd_cfg_stage_netns;
15 : extern configure_stage_t fd_cfg_stage_genesis;
16 : extern configure_stage_t fd_cfg_stage_blockstore;
17 : extern configure_stage_t fd_cfg_stage_keys;
18 :
19 : configure_stage_t * STAGES[ CONFIGURE_STAGE_COUNT ] = {
20 : &fd_cfg_stage_kill,
21 : &fd_cfg_stage_netns,
22 : &fd_cfg_stage_hugetlbfs,
23 : &fd_cfg_stage_sysctl,
24 : &fd_cfg_stage_hyperthreads,
25 : &fd_cfg_stage_ethtool_channels,
26 : &fd_cfg_stage_ethtool_gro,
27 : &fd_cfg_stage_ethtool_loopback,
28 : &fd_cfg_stage_keys,
29 : &fd_cfg_stage_genesis,
30 : #ifdef FD_HAS_NO_AGAVE
31 : NULL,
32 : #else
33 : &fd_cfg_stage_blockstore,
34 : #endif
35 : NULL,
36 : };
37 :
38 : extern fd_topo_run_tile_t fd_tile_net;
39 : extern fd_topo_run_tile_t fd_tile_netlnk;
40 : extern fd_topo_run_tile_t fd_tile_sock;
41 : extern fd_topo_run_tile_t fd_tile_quic;
42 : extern fd_topo_run_tile_t fd_tile_bundle;
43 : extern fd_topo_run_tile_t fd_tile_verify;
44 : extern fd_topo_run_tile_t fd_tile_dedup;
45 : extern fd_topo_run_tile_t fd_tile_pack;
46 : extern fd_topo_run_tile_t fd_tile_shred;
47 : extern fd_topo_run_tile_t fd_tile_sign;
48 : extern fd_topo_run_tile_t fd_tile_metric;
49 : extern fd_topo_run_tile_t fd_tile_cswtch;
50 : extern fd_topo_run_tile_t fd_tile_gui;
51 : extern fd_topo_run_tile_t fd_tile_plugin;
52 : extern fd_topo_run_tile_t fd_tile_bencho;
53 : extern fd_topo_run_tile_t fd_tile_benchg;
54 : extern fd_topo_run_tile_t fd_tile_benchs;
55 : extern fd_topo_run_tile_t fd_tile_pktgen;
56 :
57 : #ifdef FD_HAS_NO_AGAVE
58 : extern fd_topo_run_tile_t fd_tile_gossip;
59 : extern fd_topo_run_tile_t fd_tile_repair;
60 : extern fd_topo_run_tile_t fd_tile_store_int;
61 : extern fd_topo_run_tile_t fd_tile_replay;
62 : extern fd_topo_run_tile_t fd_tile_execor;
63 : extern fd_topo_run_tile_t fd_tile_replay_thread;
64 : extern fd_topo_run_tile_t fd_tile_batch;
65 : extern fd_topo_run_tile_t fd_tile_batch_thread;
66 : extern fd_topo_run_tile_t fd_tile_poh_int;
67 : extern fd_topo_run_tile_t fd_tile_sender;
68 : extern fd_topo_run_tile_t fd_tile_eqvoc;
69 : extern fd_topo_run_tile_t fd_tile_rpcserv;
70 : extern fd_topo_run_tile_t fd_tile_restart;
71 : extern fd_topo_run_tile_t fd_tile_blackhole;
72 : #else
73 : extern fd_topo_run_tile_t fd_tile_resolv;
74 : extern fd_topo_run_tile_t fd_tile_poh;
75 : extern fd_topo_run_tile_t fd_tile_bank;
76 : extern fd_topo_run_tile_t fd_tile_store;
77 : #endif
78 :
79 : fd_topo_run_tile_t * TILES[] = {
80 : &fd_tile_net,
81 : &fd_tile_netlnk,
82 : &fd_tile_sock,
83 : &fd_tile_quic,
84 : &fd_tile_bundle,
85 : &fd_tile_verify,
86 : &fd_tile_dedup,
87 : &fd_tile_pack,
88 : &fd_tile_shred,
89 : &fd_tile_sign,
90 : &fd_tile_metric,
91 : &fd_tile_cswtch,
92 : &fd_tile_gui,
93 : &fd_tile_plugin,
94 : &fd_tile_bencho,
95 : &fd_tile_benchg,
96 : &fd_tile_benchs,
97 : &fd_tile_pktgen,
98 : #ifdef FD_HAS_NO_AGAVE
99 : &fd_tile_gossip,
100 : &fd_tile_repair,
101 : &fd_tile_store_int,
102 : &fd_tile_replay,
103 : &fd_tile_replay_thread,
104 : &fd_tile_execor,
105 : &fd_tile_batch,
106 : &fd_tile_batch_thread,
107 : &fd_tile_poh_int,
108 : &fd_tile_sender,
109 : &fd_tile_eqvoc,
110 : &fd_tile_rpcserv,
111 : &fd_tile_restart,
112 : &fd_tile_blackhole,
113 : #else
114 : &fd_tile_resolv,
115 : &fd_tile_poh,
116 : &fd_tile_bank,
117 : &fd_tile_store,
118 : #endif
119 : NULL,
120 : };
121 :
122 : action_t DEV_ACTIONS[] = {
123 : { .name = "bench", .args = bench_cmd_args, .fn = bench_cmd_fn, .perm = dev_cmd_perm, .description = "Test validator TPS benchmark" },
124 : { .name = "dev", .args = dev_cmd_args, .fn = dev_cmd_fn, .perm = dev_cmd_perm, .description = "Start up a test validator" },
125 : { .name = "dev1", .args = dev1_cmd_args, .fn = dev1_cmd_fn, .perm = dev_cmd_perm, .description = "Start up a single tile" },
126 : { .name = "dump", .args = dump_cmd_args, .fn = dump_cmd_fn, .perm = NULL, .description = "Dump tango links to pcap", .is_diagnostic=1 },
127 : { .name = "flame", .args = flame_cmd_args, .fn = flame_cmd_fn, .perm = flame_cmd_perm, .description = "Capture a perf flamegraph", .is_diagnostic=1 },
128 : { .name = "help", .args = NULL, .fn = dev_help_cmd_fn, .perm = NULL, .description = "Print this help message", .is_diagnostic=1 },
129 : { .name = "load", .args = load_cmd_args, .fn = load_cmd_fn, .perm = load_cmd_perm, .description = "Load test an external validator" },
130 : { .name = "pktgen", .args = pktgen_cmd_args, .fn = pktgen_cmd_fn, .perm = dev_cmd_perm, .description = "Flood interface with invalid Ethernet frames" },
131 : { .name = "quic-trace", .args = quic_trace_cmd_args, .fn = quic_trace_cmd_fn, .perm = NULL, .description = "Trace quic tile", .is_diagnostic=1 },
132 : { .name = "txn", .args = txn_cmd_args, .fn = txn_cmd_fn, .perm = txn_cmd_perm, .description = "Send a transaction to an fddev instance" },
133 : { .name = "wksp", .args = NULL, .fn = wksp_cmd_fn, .perm = wksp_cmd_perm, .description = "Initialize workspaces" },
134 : # if FD_HAS_NO_AGAVE
135 : { .name = "gossip", .args = gossip_cmd_args, .fn = gossip_cmd_fn, .perm = gossip_cmd_perm,.description = "Run a standalone gossip node" },
136 : # endif
137 : {0}
138 : };
139 :
140 : extern char fd_log_private_path[ 1024 ];
141 :
142 0 : #define MAX_ARGC 32
143 :
144 : /* Rerun the currently executing process as root. This will never return,
145 : instead it replaces the currently executing process with a new one. */
146 : static void
147 : execve_as_root( int argc,
148 0 : char ** argv ) {
149 0 : char _current_executable_path[ PATH_MAX ];
150 0 : FD_TEST( -1!=fd_file_util_self_exe( _current_executable_path ) );
151 :
152 0 : char * args[ MAX_ARGC+4 ];
153 0 : for( int i=1; i<argc; i++ ) args[i+2] = argv[i];
154 0 : args[ 0 ] = "sudo";
155 0 : args[ 1 ] = "-E";
156 0 : args[ 2 ] = _current_executable_path;
157 : /* always override the log path to use the same one we just opened for ourselves */
158 0 : args[ argc+2 ] = "--log-path";
159 0 : args[ argc+3 ] = fd_log_private_path;
160 0 : args[ argc+4 ] = NULL;
161 :
162 : /* ok to leak these dynamic strings because we are about to execve anyway */
163 0 : char * envp[ 3 ] = {0};
164 0 : char * env;
165 0 : int idx = 0;
166 0 : if( FD_LIKELY(( env = getenv( "FIREDANCER_CONFIG_TOML" ) )) ) {
167 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "FIREDANCER_CONFIG_TOML=%s", env ) == -1 ) )
168 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
169 0 : }
170 0 : if( FD_LIKELY(( env = getenv( "TERM" ) )) ) {
171 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "TERM=%s", env ) == -1 ) )
172 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
173 0 : }
174 :
175 0 : execve( "/usr/bin/sudo", args, envp );
176 0 : FD_LOG_ERR(( "execve(sudo) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
177 0 : }
178 :
179 : static config_t config;
180 :
181 : int
182 : fddev_main( int argc,
183 0 : char ** _argv ) {
184 : /* save original arguments list in case we need to respawn the process
185 : as privileged */
186 0 : int orig_argc = argc;
187 0 : char * orig_argv[ MAX_ARGC+1 ] = {0};
188 0 : for( int i=0; i<fd_int_min( MAX_ARGC, argc ); i++ ) orig_argv[ i ] = _argv[ i ];
189 :
190 0 : if( FD_UNLIKELY( argc >= MAX_ARGC ) ) FD_LOG_ERR(( "too many arguments (%i)", argc ));
191 0 : char ** argv = _argv;
192 :
193 0 : argc--; argv++;
194 :
195 0 : fd_env_strip_cmdline_cstr( &argc, &argv, "--log-level-stderr", NULL, NULL );
196 0 : char const * log_path = fd_env_strip_cmdline_cstr( &argc, &argv, "--log-path", NULL, NULL );
197 :
198 0 : fdctl_boot( &argc, &argv, &config, log_path );
199 :
200 0 : int no_sandbox = fd_env_strip_cmdline_contains( &argc, &argv, "--no-sandbox" );
201 0 : int no_clone = fd_env_strip_cmdline_contains( &argc, &argv, "--no-clone" );
202 0 : config.development.no_clone = config.development.no_clone || no_clone;
203 0 : config.development.sandbox = config.development.sandbox && !no_sandbox && !no_clone;
204 :
205 0 : const char * action_name = "dev";
206 0 : if( FD_UNLIKELY( argc > 0 && argv[ 0 ][ 0 ] != '-' ) ) {
207 0 : action_name = argv[ 0 ];
208 0 : argc--; argv++;
209 0 : }
210 :
211 0 : action_t * action = NULL;
212 0 : for( ulong i=0; ACTIONS[ i ].name; i++ ) {
213 0 : if( FD_UNLIKELY( !strcmp( action_name, ACTIONS[ i ].name ) ) ) {
214 0 : action = &ACTIONS[ i ];
215 0 : break;
216 0 : }
217 0 : }
218 0 : for( ulong i=0; DEV_ACTIONS[ i ].name; i++ ) {
219 0 : if( FD_UNLIKELY( !strcmp( action_name, DEV_ACTIONS[ i ].name ) ) ) {
220 0 : action = &DEV_ACTIONS[ i ];
221 0 : break;
222 0 : }
223 0 : }
224 :
225 0 : if( FD_UNLIKELY( !action ) ) FD_LOG_ERR(( "unknown subcommand `%s`", action_name ));
226 :
227 0 : int is_allowed_live = action->is_diagnostic==1;
228 0 : if( FD_UNLIKELY( config.is_live_cluster && !is_allowed_live ) )
229 0 : FD_LOG_ERR(( "The `fddev` command is for development and test environments but your "
230 0 : "configuration targets a live cluster. Use `fdctl` if this is a "
231 0 : "production environment" ));
232 :
233 0 : args_t args = {0};
234 0 : if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
235 0 : if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
236 :
237 : /* Check if we are appropriately permissioned to run the desired
238 : command. */
239 0 : if( FD_LIKELY( action->perm ) ) {
240 0 : fd_cap_chk_t * chk = fd_cap_chk_join( fd_cap_chk_new( __builtin_alloca_with_align( fd_cap_chk_footprint(), FD_CAP_CHK_ALIGN ) ) );
241 0 : action->perm( &args, chk, &config );
242 0 : ulong err_cnt = fd_cap_chk_err_cnt( chk );
243 0 : if( FD_UNLIKELY( err_cnt ) ) {
244 0 : if( FD_UNLIKELY( !geteuid() ) ) {
245 0 : for( ulong i=0UL; i<err_cnt; i++ ) FD_LOG_WARNING(( "%s", fd_cap_chk_err( chk, i ) ));
246 0 : FD_LOG_ERR(( "insufficient permissions to execute command `%s` when running as root. "
247 0 : "fddev is likely being run with a reduced capability bounding set.", action_name ));
248 0 : }
249 0 : execve_as_root( orig_argc, orig_argv );
250 0 : }
251 0 : }
252 :
253 : /* run the command */
254 0 : action->fn( &args, &config );
255 0 : return 0;
256 0 : }
|