Line data Source code
1 : #define _GNU_SOURCE
2 : #include "fd_dev_boot.h"
3 :
4 : #include "../../shared/fd_config.h"
5 : #include "../../shared/fd_action.h"
6 : #include "../../shared/boot/fd_boot.h"
7 : #include "../../platform/fd_file_util.h"
8 :
9 : #include <errno.h>
10 : #include <unistd.h>
11 : #include <stdlib.h>
12 : #include <stdio.h>
13 : #include <sys/types.h>
14 : #include <sys/stat.h>
15 :
16 : extern char fd_log_private_path[ 1024 ];
17 :
18 : extern action_t * ACTIONS[];
19 :
20 0 : #define MAX_ARGC 32
21 :
22 : /* Rerun the currently executing process as root. This will never return,
23 : instead it replaces the currently executing process with a new one. */
24 : static void
25 : execve_as_root( int argc,
26 0 : char ** argv ) {
27 0 : char _current_executable_path[ PATH_MAX ];
28 0 : FD_TEST( -1!=fd_file_util_self_exe( _current_executable_path ) );
29 :
30 0 : char * args[ MAX_ARGC+4 ];
31 0 : for( int i=1; i<argc; i++ ) args[i+2] = argv[i];
32 0 : args[ 0 ] = "sudo";
33 0 : args[ 1 ] = "-E";
34 0 : args[ 2 ] = _current_executable_path;
35 : /* always override the log path to use the same one we just opened for ourselves */
36 0 : args[ argc+2 ] = "--log-path";
37 0 : args[ argc+3 ] = fd_log_private_path;
38 0 : args[ argc+4 ] = NULL;
39 :
40 : /* ok to leak these dynamic strings because we are about to execve anyway */
41 0 : char * envp[ 4 ] = {0};
42 0 : char * env;
43 0 : int idx = 0;
44 0 : if( FD_LIKELY(( env = getenv( "FIREDANCER_CONFIG_TOML" ) )) ) {
45 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "FIREDANCER_CONFIG_TOML=%s", env ) == -1 ) )
46 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
47 0 : }
48 0 : if( FD_LIKELY(( env = getenv( "TERM" ) )) ) {
49 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "TERM=%s", env ) == -1 ) )
50 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
51 0 : }
52 0 : if( FD_UNLIKELY( asprintf( &envp[ idx++ ], "FD_LOG_PATH_ANNOUNCED=%s", fd_log_private_path ) == -1 ) )
53 0 : FD_LOG_ERR(( "asprintf() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
54 :
55 0 : execve( "/usr/bin/sudo", args, envp );
56 0 : FD_LOG_ERR(( "execve(sudo) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
57 0 : }
58 :
59 : config_t config;
60 :
61 : void
62 0 : fd_global_options_help( fd_action_help_t * help ) {
63 0 : fd_action_help_arg( help, "--config", "<path>", "Path to a configuration TOML file" );
64 0 : fd_action_help_arg( help, "--mainnet", NULL, "Use Solana mainnet defaults" );
65 0 : fd_action_help_arg( help, "--testnet", NULL, "Use Solana testnet defaults" );
66 0 : fd_action_help_arg( help, "--devnet", NULL, "Use Solana devnet defaults" );
67 0 : fd_action_help_arg( help, "--mainnet-jito", NULL, "Use Solana mainnet defaults with the Jito relayer/bundles" );
68 0 : fd_action_help_arg( help, "--testnet-jito", NULL, "Use Solana testnet defaults with the Jito relayer/bundles" );
69 0 : fd_action_help_arg( help, "--log-path", "<path>", "Path to write the log file to" );
70 0 : fd_action_help_arg( help, "--log-level-stderr", "<level>", "Minimum log level to print to stderr" );
71 0 : fd_action_help_arg( help, "--no-sandbox", NULL, "Disable the security sandbox (development only)" );
72 0 : fd_action_help_arg( help, "--no-clone", NULL, "Run all tiles in a single process instead of one per tile (development only)" );
73 0 : fd_action_help_arg( help, "--max-live-slots", "<count>", "Override the [runtime.max_live_slots] configuration (development only)" );
74 0 : fd_action_help_arg( help, "--efficient", NULL, "Override the layout mode to \"efficient\" so tiles sleep when idle" );
75 0 : fd_action_help_arg( help, "--version", NULL, "Show the current software version" );
76 0 : fd_action_help_arg( help, "--help/-h", NULL, "Print this help message" );
77 0 : }
78 :
79 : int
80 : fd_dev_main( int argc,
81 : char ** _argv,
82 : fd_config_file_t * const * configs,
83 0 : void (* topo_init )( config_t * config ) ) {
84 0 : fd_version_private_boot( &argc, &_argv );
85 : /* save original arguments list in case we need to respawn the process
86 : as privileged */
87 0 : int orig_argc = argc;
88 0 : char * orig_argv[ MAX_ARGC+1 ] = {0};
89 0 : for( int i=0; i<fd_int_min( MAX_ARGC, argc ); i++ ) orig_argv[ i ] = _argv[ i ];
90 :
91 0 : if( FD_UNLIKELY( argc >= MAX_ARGC ) ) FD_LOG_ERR(( "too many arguments (%i)", argc ));
92 0 : char ** argv = _argv;
93 :
94 0 : argc--; argv++;
95 :
96 0 : fd_env_strip_cmdline_cstr( &argc, &argv, "--log-level-stderr", NULL, NULL );
97 0 : char const * log_path = fd_env_strip_cmdline_cstr( &argc, &argv, "--log-path", NULL, NULL );
98 :
99 0 : int no_sandbox = fd_env_strip_cmdline_contains( &argc, &argv, "--no-sandbox" );
100 0 : int no_clone = fd_env_strip_cmdline_contains( &argc, &argv, "--no-clone" );
101 0 : int efficient = fd_env_strip_cmdline_contains( &argc, &argv, "--efficient" );
102 :
103 0 : ulong max_live_slots = fd_env_strip_cmdline_ulong( &argc, &argv, "--max-live-slots", NULL, 0UL );
104 :
105 0 : const char * opt_user_config_path = fd_env_strip_cmdline_cstr(
106 0 : &argc,
107 0 : &argv,
108 0 : "--config",
109 0 : "FIREDANCER_CONFIG_TOML",
110 0 : NULL );
111 :
112 0 : const char * action_name = "dev";
113 0 : if( FD_LIKELY( argc > 0 && !strcmp( argv[ 0 ], "--version" ) ) ) {
114 0 : action_name = "version";
115 0 : argc--; argv++;
116 0 : } else if( FD_LIKELY( argc > 0 && ( !strcmp( argv[ 0 ], "--help" ) || !strcmp( argv[ 0 ], "-h" ) ) ) ) {
117 0 : action_name = "help";
118 0 : argc--; argv++;
119 0 : } else if( FD_UNLIKELY( argc > 0 && argv[ 0 ][ 0 ] != '-' ) ) {
120 0 : action_name = argv[ 0 ];
121 0 : argc--; argv++;
122 0 : }
123 :
124 0 : action_t * action = NULL;
125 0 : for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
126 0 : if( FD_UNLIKELY( !strcmp( action_name, ACTIONS[ i ]->name ) ) ) {
127 0 : action = ACTIONS[ i ];
128 0 : if( FD_UNLIKELY( action->is_immediate ) ) {
129 0 : action->fn( NULL, NULL );
130 0 : return 0;
131 0 : }
132 0 : break;
133 0 : }
134 0 : }
135 :
136 0 : if( FD_UNLIKELY( !action ) ) {
137 0 : fprintf( stderr, "unknown subcommand `%s`\n", action_name );
138 0 : exit( 1 );
139 0 : }
140 :
141 0 : int help_argc = argc; char ** help_argv = argv;
142 0 : if( FD_UNLIKELY( fd_env_strip_cmdline_contains( &help_argc, &help_argv, "--help" ) ||
143 0 : fd_env_strip_cmdline_contains( &help_argc, &help_argv, "-h" ) ) ) {
144 0 : fd_action_help_print( action );
145 0 : return 0;
146 0 : }
147 :
148 0 : # if !FD_HAS_ASAN && !FD_HAS_MSAN
149 0 : fd_log_enable_signal_handler();
150 0 : # endif
151 0 : int load_topo = fd_main_init( &argc, &argv, &config, opt_user_config_path, action->is_local_cluster, log_path, configs, 1 /* dev */ );
152 0 : if( FD_LIKELY( load_topo ) ) fd_cstr_ncpy( config.action, action->name, sizeof( config.action ) );
153 :
154 0 : if( FD_UNLIKELY( config.is_live_cluster && (no_clone || no_sandbox) ) )
155 0 : FD_LOG_ERR(( "trying to join a live cluster, but %s is a development only flag", no_clone ? "--no-clone" : "--no-sandbox" ));
156 :
157 0 : config.development.no_clone = config.development.no_clone || no_clone;
158 0 : config.development.sandbox = config.development.sandbox && !no_sandbox && !config.development.no_clone;
159 :
160 0 : if( FD_LIKELY( load_topo ) ) {
161 0 : if( FD_UNLIKELY( max_live_slots ) ) config.firedancer.runtime.max_live_slots = max_live_slots;
162 0 : if( FD_UNLIKELY( efficient ) ) fd_cstr_ncpy( config.firedancer.layout.mode, "efficient", sizeof(config.firedancer.layout.mode) );
163 0 : if( FD_LIKELY( action->topo ) ) action->topo( &config );
164 0 : else topo_init( &config );
165 0 : }
166 :
167 0 : args_t args = {0};
168 0 : if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
169 0 : if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
170 :
171 : /* Check if we are appropriately permissioned to run the desired
172 : command. */
173 0 : if( FD_LIKELY( action->perm ) ) {
174 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 ) ) );
175 0 : action->perm( &args, chk, &config );
176 0 : ulong err_cnt = fd_cap_chk_err_cnt( chk );
177 0 : if( FD_UNLIKELY( err_cnt ) ) {
178 0 : if( FD_UNLIKELY( !geteuid() ) ) {
179 0 : for( ulong i=0UL; i<err_cnt; i++ ) FD_LOG_WARNING(( "%s", fd_cap_chk_err( chk, i ) ));
180 0 : FD_LOG_ERR(( "insufficient permissions to execute command `%s` when running as root. "
181 0 : "firedancer-dev is likely being run with a reduced capability bounding set.", action_name ));
182 0 : }
183 0 : FD_LOG_INFO(( "insufficient permissions to execute command `%s`, rerunning as root", action_name ));
184 0 : execve_as_root( orig_argc, orig_argv );
185 0 : }
186 0 : }
187 :
188 : /* run the command */
189 0 : action->fn( &args, &config );
190 0 : return 0;
191 0 : }
|