Line data Source code
1 : #define _GNU_SOURCE
2 : #include "fddev.h"
3 :
4 : #include "../fdctl/configure/configure.h"
5 :
6 : #include <unistd.h>
7 : #include <stdlib.h>
8 : #include <stdio.h>
9 : #include <sys/types.h>
10 : #include <sys/stat.h>
11 :
12 : extern configure_stage_t _kill;
13 : extern configure_stage_t netns;
14 : extern configure_stage_t genesis;
15 : extern configure_stage_t blockstore;
16 : extern configure_stage_t keys;
17 :
18 : configure_stage_t * STAGES[ CONFIGURE_STAGE_COUNT ] = {
19 : &_kill,
20 : &netns,
21 : &hugetlbfs,
22 : &sysctl,
23 : ðtool_channels,
24 : ðtool_gro,
25 : &keys,
26 : &genesis,
27 : #ifdef FD_HAS_NO_AGAVE
28 : NULL,
29 : #else
30 : &blockstore,
31 : #endif
32 : NULL,
33 : };
34 :
35 : extern fd_topo_run_tile_t fd_tile_net;
36 : extern fd_topo_run_tile_t fd_tile_quic;
37 : extern fd_topo_run_tile_t fd_tile_verify;
38 : extern fd_topo_run_tile_t fd_tile_dedup;
39 : extern fd_topo_run_tile_t fd_tile_resolv;
40 : extern fd_topo_run_tile_t fd_tile_pack;
41 : extern fd_topo_run_tile_t fd_tile_bank;
42 : extern fd_topo_run_tile_t fd_tile_poh;
43 : extern fd_topo_run_tile_t fd_tile_shred;
44 : extern fd_topo_run_tile_t fd_tile_store;
45 : extern fd_topo_run_tile_t fd_tile_sign;
46 : extern fd_topo_run_tile_t fd_tile_metric;
47 : extern fd_topo_run_tile_t fd_tile_cswtch;
48 : extern fd_topo_run_tile_t fd_tile_gui;
49 : extern fd_topo_run_tile_t fd_tile_plugin;
50 : extern fd_topo_run_tile_t fd_tile_blackhole;
51 : extern fd_topo_run_tile_t fd_tile_bencho;
52 : extern fd_topo_run_tile_t fd_tile_benchg;
53 : extern fd_topo_run_tile_t fd_tile_benchs;
54 :
55 : #ifdef FD_HAS_NO_AGAVE
56 : extern fd_topo_run_tile_t fd_tile_gossip;
57 : extern fd_topo_run_tile_t fd_tile_repair;
58 : extern fd_topo_run_tile_t fd_tile_store_int;
59 : extern fd_topo_run_tile_t fd_tile_replay;
60 : extern fd_topo_run_tile_t fd_tile_replay_thread;
61 : extern fd_topo_run_tile_t fd_tile_poh_int;
62 : extern fd_topo_run_tile_t fd_tile_sender;
63 : extern fd_topo_run_tile_t fd_tile_eqvoc;
64 : extern fd_topo_run_tile_t fd_tile_rpcserv;
65 : #endif
66 :
67 : fd_topo_run_tile_t * TILES[] = {
68 : &fd_tile_net,
69 : &fd_tile_quic,
70 : &fd_tile_verify,
71 : &fd_tile_dedup,
72 : &fd_tile_resolv,
73 : &fd_tile_pack,
74 : &fd_tile_bank,
75 : &fd_tile_poh,
76 : &fd_tile_shred,
77 : &fd_tile_store,
78 : &fd_tile_sign,
79 : &fd_tile_metric,
80 : &fd_tile_cswtch,
81 : &fd_tile_gui,
82 : &fd_tile_plugin,
83 : &fd_tile_blackhole,
84 : &fd_tile_bencho,
85 : &fd_tile_benchg,
86 : &fd_tile_benchs,
87 : #ifdef FD_HAS_NO_AGAVE
88 : &fd_tile_gossip,
89 : &fd_tile_repair,
90 : &fd_tile_store_int,
91 : &fd_tile_replay,
92 : &fd_tile_replay_thread,
93 : &fd_tile_poh_int,
94 : &fd_tile_sender,
95 : &fd_tile_eqvoc,
96 : &fd_tile_rpcserv,
97 : #endif
98 : NULL,
99 : };
100 :
101 : static action_t DEV_ACTIONS[] = {
102 : { .name = "dev", .args = dev_cmd_args, .fn = dev_cmd_fn, .perm = dev_cmd_perm },
103 : { .name = "wksp", .args = NULL, .fn = wksp_cmd_fn, .perm = wksp_cmd_perm },
104 : { .name = "dev1", .args = dev1_cmd_args, .fn = dev1_cmd_fn, .perm = dev_cmd_perm },
105 : { .name = "txn", .args = txn_cmd_args, .fn = txn_cmd_fn, .perm = txn_cmd_perm },
106 : { .name = "bench", .args = bench_cmd_args, .fn = bench_cmd_fn, .perm = bench_cmd_perm },
107 : { .name = "load", .args = load_cmd_args, .fn = load_cmd_fn, .perm = load_cmd_perm },
108 : { .name = "dump", .args = dump_cmd_args, .fn = dump_cmd_fn, .perm = NULL },
109 : { .name = "flame", .args = flame_cmd_args, .fn = flame_cmd_fn, .perm = flame_cmd_perm },
110 : };
111 :
112 : extern char fd_log_private_path[ 1024 ];
113 :
114 0 : #define MAX_ARGC 32
115 :
116 : /* Rerun the currently executing process as root. This will never return,
117 : instead it replaces the currently executing process with a new one. */
118 : static void
119 : execve_as_root( int argc,
120 0 : char ** argv ) {
121 0 : char _current_executable_path[ PATH_MAX ];
122 0 : current_executable_path( _current_executable_path );
123 :
124 0 : char * args[ MAX_ARGC+4 ];
125 0 : for( int i=1; i<argc; i++ ) args[i+2] = argv[i];
126 0 : args[ 0 ] = "sudo";
127 0 : args[ 1 ] = "-E";
128 0 : args[ 2 ] = _current_executable_path;
129 : /* always override the log path to use the same one we just opened for ourselves */
130 0 : args[ argc+2 ] = "--log-path";
131 0 : args[ argc+3 ] = fd_log_private_path;
132 0 : args[ argc+4 ] = NULL;
133 :
134 : /* ok to leak these dynamic strings because we are about to execve anyway */
135 0 : char * envp[ 3 ] = {0};
136 0 : char * env;
137 0 : int idx = 0;
138 0 : if( FD_LIKELY(( env = getenv( "FIREDANCER_CONFIG_TOML" ) )) ) {
139 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "FIREDANCER_CONFIG_TOML=%s", env ) == -1 ) )
140 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
141 0 : }
142 0 : if( FD_LIKELY(( env = getenv( "TERM" ) )) ) {
143 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "TERM=%s", env ) == -1 ) )
144 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
145 0 : }
146 :
147 0 : execve( "/usr/bin/sudo", args, envp );
148 0 : FD_LOG_ERR(( "execve(sudo) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
149 0 : }
150 :
151 : static config_t config;
152 :
153 : int
154 : fddev_main( int argc,
155 0 : char ** _argv ) {
156 : /* save original arguments list in case we need to respawn the process
157 : as privileged */
158 0 : int orig_argc = argc;
159 0 : char * orig_argv[ MAX_ARGC+1 ] = {0};
160 0 : for( int i=0; i<fd_int_min( MAX_ARGC, argc ); i++ ) orig_argv[ i ] = _argv[ i ];
161 :
162 0 : if( FD_UNLIKELY( argc >= MAX_ARGC ) ) FD_LOG_ERR(( "too many arguments (%i)", argc ));
163 0 : char ** argv = _argv;
164 :
165 0 : argc--; argv++;
166 :
167 0 : fd_env_strip_cmdline_cstr( &argc, &argv, "--log-level-stderr", NULL, NULL );
168 0 : char const * log_path = fd_env_strip_cmdline_cstr( &argc, &argv, "--log-path", NULL, NULL );
169 :
170 0 : fdctl_boot( &argc, &argv, &config, log_path );
171 :
172 : /* load configuration and command line parsing */
173 0 : if( FD_UNLIKELY( config.is_live_cluster ) )
174 0 : FD_LOG_ERR(( "The `fddev` command is for development and test environments but your "
175 0 : "configuration targets a live cluster. Use `fdctl` if this is a "
176 0 : "production environment" ));
177 :
178 0 : int no_sandbox = fd_env_strip_cmdline_contains( &argc, &argv, "--no-sandbox" );
179 0 : int no_clone = fd_env_strip_cmdline_contains( &argc, &argv, "--no-clone" );
180 0 : config.development.no_clone = config.development.no_clone || no_clone;
181 0 : config.development.sandbox = config.development.sandbox && !no_sandbox && !no_clone;
182 :
183 0 : const char * action_name = "dev";
184 0 : if( FD_UNLIKELY( argc > 0 && argv[ 0 ][ 0 ] != '-' ) ) {
185 0 : action_name = argv[ 0 ];
186 0 : argc--; argv++;
187 0 : }
188 :
189 0 : action_t * action = NULL;
190 0 : for( ulong i=0; i<sizeof(ACTIONS)/sizeof(ACTIONS[ 0 ]); i++ ) {
191 0 : if( FD_UNLIKELY( !strcmp( action_name, ACTIONS[ i ].name ) ) ) {
192 0 : action = &ACTIONS[ i ];
193 0 : break;
194 0 : }
195 0 : }
196 0 : for( ulong i=0; i<sizeof(DEV_ACTIONS)/sizeof(DEV_ACTIONS[ 0 ]); i++ ) {
197 0 : if( FD_UNLIKELY( !strcmp( action_name, DEV_ACTIONS[ i ].name ) ) ) {
198 0 : action = &DEV_ACTIONS[ i ];
199 0 : break;
200 0 : }
201 0 : }
202 :
203 0 : if( FD_UNLIKELY( !action ) ) FD_LOG_ERR(( "unknown subcommand `%s`", action_name ));
204 :
205 0 : args_t args = {0};
206 0 : if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
207 0 : if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
208 :
209 : /* Check if we are appropriately permissioned to run the desired
210 : command. */
211 0 : if( FD_LIKELY( action->perm ) ) {
212 0 : fd_caps_ctx_t caps[1] = {0};
213 0 : action->perm( &args, caps, &config );
214 0 : if( FD_UNLIKELY( caps->err_cnt ) ) {
215 0 : if( FD_UNLIKELY( !geteuid() ) ) {
216 0 : for( ulong i=0; i<caps->err_cnt; i++ ) FD_LOG_WARNING(( "%s", caps->err[ i ] ));
217 0 : FD_LOG_ERR(( "insufficient permissions to execute command `%s` when running as root. "
218 0 : "fddev is likely being run with a reduced capability bounding set.", action_name ));
219 0 : }
220 0 : execve_as_root( orig_argc, orig_argv );
221 0 : }
222 0 : }
223 :
224 : /* run the command */
225 0 : action->fn( &args, &config );
226 0 : return 0;
227 0 : }
|