LCOV - code coverage report
Current view: top level - app/shared/boot - fd_boot.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 252 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_boot.h"
       3             : 
       4             : #include "../fd_config.h"
       5             : #include "../fd_action.h"
       6             : #include "../../platform/fd_file_util.h"
       7             : #include "../../../disco/topo/fd_topo.h"
       8             : 
       9             : #include <errno.h>
      10             : #include <unistd.h>
      11             : #include <fcntl.h>
      12             : #include <sys/mman.h>
      13             : 
      14             : extern action_t * ACTIONS[];
      15             : extern fd_topo_run_tile_t * TILES[];
      16             : 
      17             : fd_topo_run_tile_t
      18           0 : fdctl_tile_run( fd_topo_tile_t const * tile ) {
      19           0 :   for( ulong i=0UL; TILES[ i ]; i++ ) {
      20           0 :     if( !strcmp( tile->name, TILES[ i ]->name ) ) return *TILES[ i ];
      21           0 :   }
      22           0 :   FD_LOG_ERR(( "tile `%s` not found", tile->name ));
      23           0 :   return (fd_topo_run_tile_t){0};
      24           0 : }
      25             : 
      26             : static void
      27             : copy_config_from_fd( int        config_fd,
      28           0 :                      config_t * config ) {
      29           0 :   uchar * bytes = mmap( NULL, sizeof( config_t ), PROT_READ, MAP_PRIVATE, config_fd, 0 );
      30           0 :   if( FD_UNLIKELY( bytes == MAP_FAILED ) ) FD_LOG_ERR(( "mmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      31           0 :   fd_memcpy( config, bytes, sizeof( config_t ) );
      32           0 :   if( FD_UNLIKELY( munmap( bytes, sizeof( config_t ) ) ) ) FD_LOG_ERR(( "munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      33           0 :   if( FD_UNLIKELY( close( config_fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      34           0 : }
      35             : 
      36             : static void
      37             : determine_override_config( int *                      pargc,
      38             :                            char ***                   pargv,
      39             :                            fd_config_file_t * const * configs,
      40             :                            char const **              override_config,
      41             :                            char const **              override_config_path,
      42           0 :                            ulong *                    override_config_sz ) {
      43           0 :   int testnet = fd_env_strip_cmdline_contains( pargc, pargv, "--testnet" );
      44           0 :   if( FD_UNLIKELY( testnet ) ) {
      45           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      46           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "testnet" ) ) ) {
      47           0 :         *override_config = (char const *)configs[ i ]->data;
      48           0 :         *override_config_path = configs[ i ]->name;
      49           0 :         *override_config_sz = configs[ i ]->data_sz;
      50           0 :         return;
      51           0 :       }
      52           0 :     }
      53             : 
      54           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no testnet config found" ));
      55           0 :   }
      56             : 
      57           0 :   int devnet = fd_env_strip_cmdline_contains( pargc, pargv, "--devnet" );
      58           0 :   if( FD_UNLIKELY( devnet ) ) {
      59           0 :     if( FD_UNLIKELY( testnet ) ) FD_LOG_ERR(( "cannot specify both --testnet and --devnet" ));
      60           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      61           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "devnet" ) ) ) {
      62           0 :         *override_config = (char const *)configs[ i ]->data;
      63           0 :         *override_config_path = configs[ i ]->name;
      64           0 :         *override_config_sz = configs[ i ]->data_sz;
      65           0 :         return;
      66           0 :       }
      67           0 :     }
      68             : 
      69           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no devnet config found" ));
      70           0 :   }
      71             : 
      72           0 :   int mainnet = fd_env_strip_cmdline_contains( pargc, pargv, "--mainnet" );
      73           0 :   if( FD_UNLIKELY( mainnet ) ) {
      74           0 :     if( FD_UNLIKELY( testnet || devnet ) ) FD_LOG_ERR(( "cannot specify both --testnet or --devnet and --mainnet" ));
      75           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      76           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "mainnet" ) ) ) {
      77           0 :         *override_config = (char const *)configs[ i ]->data;
      78           0 :         *override_config_path = configs[ i ]->name;
      79           0 :         *override_config_sz = configs[ i ]->data_sz;
      80           0 :         return;
      81           0 :       }
      82           0 :     }
      83             : 
      84           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no mainnet config found" ));
      85           0 :   }
      86             : 
      87           0 :   int testnet_jito = fd_env_strip_cmdline_contains( pargc, pargv, "--testnet-jito" );
      88           0 :   if( FD_UNLIKELY( testnet_jito ) ) {
      89           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      90           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "testnet-jito" ) ) ) {
      91           0 :         *override_config = (char const *)configs[ i ]->data;
      92           0 :         *override_config_path = configs[ i ]->name;
      93           0 :         *override_config_sz = configs[ i ]->data_sz;
      94           0 :         return;
      95           0 :       }
      96           0 :     }
      97             : 
      98           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no testnet-jito config found" ));
      99           0 :   }
     100             : 
     101           0 :   int mainnet_jito = fd_env_strip_cmdline_contains( pargc, pargv, "--mainnet-jito" );
     102           0 :   if( FD_UNLIKELY( mainnet_jito ) ) {
     103           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     104           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "mainnet-jito" ) ) ) {
     105           0 :         *override_config = (char const *)configs[ i ]->data;
     106           0 :         *override_config_path = configs[ i ]->name;
     107           0 :         *override_config_sz = configs[ i ]->data_sz;
     108           0 :         return;
     109           0 :       }
     110           0 :     }
     111             : 
     112           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no mainnet-jito config found" ));
     113           0 :   }
     114           0 : }
     115             : 
     116             : __attribute__((weak)) void
     117           0 : fd_global_options_help( fd_action_help_t * help ) {
     118           0 :   fd_action_help_arg( help, "--config",       "<path>", "Path to a configuration TOML file" );
     119           0 :   fd_action_help_arg( help, "--mainnet",      NULL,     "Use Solana mainnet defaults" );
     120           0 :   fd_action_help_arg( help, "--testnet",      NULL,     "Use Solana testnet defaults" );
     121           0 :   fd_action_help_arg( help, "--devnet",       NULL,     "Use Solana devnet defaults" );
     122           0 :   fd_action_help_arg( help, "--mainnet-jito", NULL,     "Use Solana mainnet defaults with the Jito relayer/bundles" );
     123           0 :   fd_action_help_arg( help, "--testnet-jito", NULL,     "Use Solana testnet defaults with the Jito relayer/bundles" );
     124           0 :   fd_action_help_arg( help, "--standby",      NULL,     "Boot as a failover standby under a junk identity" );
     125           0 :   fd_action_help_arg( help, "--version",      NULL,     "Show the current software version" );
     126           0 :   fd_action_help_arg( help, "--help/-h",      NULL,     "Print this help message" );
     127           0 : }
     128             : 
     129             : int
     130             : fd_main_init( int *                      pargc,
     131             :               char ***                   pargv,
     132             :               config_t   *               config,
     133             :               const char *               opt_user_config_path,
     134             :               int                        is_local_cluster,
     135             :               int                        no_topo,
     136             :               char const *               log_path,
     137             :               fd_config_file_t * const * configs,
     138           0 :               int                        dev ) {
     139           0 :   fd_log_enable_unclean_exit(); /* Don't call atexit handlers on FD_LOG_ERR */
     140           0 :   fd_log_level_core_set( 5 ); /* Don't dump core for FD_LOG_ERR during boot */
     141           0 :   fd_log_colorize_set( fd_log_should_colorize() ); /* Colorize during boot until we can determine from config */
     142           0 :   fd_log_level_stderr_set( 2 ); /* Only NOTICE and above will be logged during boot until fd_log is initialized */
     143             : 
     144           0 :   int config_fd = fd_env_strip_cmdline_int( pargc, pargv, "--config-fd", NULL, -1 );
     145             : 
     146           0 :   fd_memset( config, 0, sizeof( config_t ) );
     147           0 :   char * thread = "";
     148           0 :   if( FD_UNLIKELY( config_fd >= 0 ) ) {
     149           0 :     copy_config_from_fd( config_fd, config );
     150             :     /* tick_per_ns needs to be synchronized across processes so that
     151             :        they can coordinate on metrics measurement. */
     152           0 :     fd_tempo_set_tick_per_ns( config->tick_per_ns_mu, config->tick_per_ns_sigma );
     153           0 :   } else {
     154           0 :     char * user_config = NULL;
     155           0 :     ulong user_config_sz = 0UL;
     156           0 :     if( FD_LIKELY( opt_user_config_path ) ) {
     157           0 :       user_config = fd_file_util_read_all( opt_user_config_path, &user_config_sz );
     158           0 :       if( FD_UNLIKELY( user_config==MAP_FAILED ) ) FD_LOG_ERR(( "failed to read user config file `%s` (%d-%s)", opt_user_config_path, errno, fd_io_strerror( errno ) ));
     159           0 :     }
     160             : 
     161           0 :     char const * default_config = NULL;
     162           0 :     ulong default_config_sz = 0UL;
     163           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     164           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "default" ) ) ) {
     165           0 :         default_config = (char const *)configs[ i ]->data;
     166           0 :         default_config_sz = configs[ i ]->data_sz;
     167           0 :         break;
     168           0 :       }
     169           0 :     }
     170           0 :     if( FD_UNLIKELY( !default_config ) ) FD_LOG_ERR(( "no default config found" ));
     171             : 
     172           0 :     char const * override_config = NULL;
     173           0 :     char const * override_config_path = NULL;
     174           0 :     ulong override_config_sz = 0UL;
     175           0 :     determine_override_config( pargc, pargv, configs,
     176           0 :                                &override_config, &override_config_path, &override_config_sz );
     177           0 :     int standby = fd_env_strip_cmdline_contains( pargc, pargv, "--standby" );
     178             : 
     179             :     /* Only tiles consume the tick rate, skip calibrating it. */
     180           0 :     if( FD_UNLIKELY( no_topo ) ) fd_tempo_set_tick_per_ns( 0., 0. );
     181             : 
     182           0 :     fd_config_load( is_local_cluster, default_config, default_config_sz, override_config, override_config_path, override_config_sz, user_config, user_config_sz, opt_user_config_path, config, dev );
     183             : 
     184             :     /* --standby is a shorthand for [failover.boot_to_standby], applied
     185             :        before the topology picks the key every tile boots under. */
     186           0 :     if( FD_UNLIKELY( standby ) ) {
     187           0 :       if( FD_UNLIKELY( !config->firedancer.failover.enabled ) ) FD_LOG_ERR(( "--standby needs [failover.enabled] set to true" ));
     188           0 :       config->firedancer.failover.boot_to_standby = 1;
     189           0 :     }
     190             : 
     191           0 :     if( FD_UNLIKELY( user_config && -1==munmap( user_config, user_config_sz ) ) ) FD_LOG_ERR(( "munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     192             : 
     193           0 :     config->log.log_fd  = -1;
     194           0 :     config->has_user_config = !!opt_user_config_path;
     195           0 :     thread = "main";
     196           0 :     if( FD_UNLIKELY( log_path ) )
     197           0 :       strncpy( config->log.path, log_path, sizeof( config->log.path ) - 1 );
     198           0 :   }
     199             : 
     200           0 :   char * shmem_args[ 3 ];
     201             :   /* pass in --shmem-path value from the config */
     202           0 :   shmem_args[ 0 ] = "--shmem-path";
     203           0 :   shmem_args[ 1 ] = config->hugetlbfs.mount_path;
     204           0 :   shmem_args[ 2 ] = NULL;
     205           0 :   char ** argv = shmem_args;
     206           0 :   int     argc = 2;
     207             : 
     208           0 :   ulong pid = fd_sandbox_getpid(); /* Need to read /proc since we might be in a PID namespace now */;
     209             : 
     210           0 :   log_path = config->log.path;
     211           0 :   if( FD_LIKELY( config->log.path[ 0 ]=='\0' ) ) log_path = NULL;
     212             : 
     213             :   /* Switch to the sandbox uid/gid for log file creation, so it's always
     214             :      owned by that user. */
     215             : 
     216           0 :   gid_t gid = getgid();
     217           0 :   uid_t uid = getuid();
     218           0 :   if( FD_LIKELY( !gid && setegid( config->gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     219           0 :   if( FD_LIKELY( !uid && seteuid( config->uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     220             : 
     221           0 :   int boot_silent = config_fd>=0;
     222           0 :   fd_log_private_boot_custom( 0UL,
     223           0 :                               config->name,
     224           0 :                               0UL,    /* Thread ID will be initialized later */
     225           0 :                               thread, /* Thread will be initialized later */
     226           0 :                               0UL,
     227           0 :                               config->hostname,
     228           0 :                               fd_log_private_cpu_id_default(),
     229           0 :                               NULL,
     230           0 :                               pid,
     231           0 :                               NULL,
     232           0 :                               pid,
     233           0 :                               config->uid,
     234           0 :                               config->user,
     235           0 :                               1,
     236           0 :                               config->log.colorize1,
     237           0 :                               boot_silent ? 2 : config->log.level_logfile1,
     238           0 :                               boot_silent ? 2 : config->log.level_stderr1,
     239           0 :                               config->log.level_flush1,
     240           0 :                               5,
     241           0 :                               config->log.log_fd,
     242           0 :                               log_path );
     243             : 
     244           0 :   if( FD_UNLIKELY( seteuid( uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     245           0 :   if( FD_UNLIKELY( setegid( gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     246             : 
     247           0 :   config->log.log_fd = fd_log_private_logfile_fd();
     248           0 :   fd_shmem_private_boot( &argc, &argv );
     249           0 :   fd_tile_private_boot( 0, NULL );
     250             : 
     251           0 :   fd_log_level_logfile_set( config->log.level_logfile1 );
     252           0 :   fd_log_level_stderr_set( config->log.level_stderr1 );
     253           0 :   fd_log_level_flush_set( config->log.level_flush1 );
     254             : 
     255             :   /* When auto config info/decisions are collected is before when the
     256             :      log file is setup, so the logging of this info must be done separately. */
     257           0 :   if( !boot_silent ) FD_LOG_INFO(( "%s", config->auto_config_log ));
     258             : 
     259             : #if !FD_HAS_SSE
     260             :   if( !boot_silent ) FD_LOG_WARNING(( "this CPU architecture is unsupported, expect bugs" ));
     261             : #endif
     262             : 
     263           0 :   return config_fd<0 && !no_topo;
     264           0 : }
     265             : 
     266             : static config_t config;
     267             : 
     268             : int
     269             : fd_main( int                        argc,
     270             :          char **                    _argv,
     271             :          fd_config_file_t * const * configs,
     272           0 :          void (* topo_init )( config_t * config ) ) {
     273           0 :   fd_version_private_boot( &argc, &_argv );
     274           0 :   char ** argv = _argv;
     275           0 :   argc--; argv++;
     276             : 
     277             :   /* Short circuit evaluating help and version commands so that we don't
     278             :      need to load and evaluate the entire config file to run them.
     279             :      This is useful for some operators in CI environments where, for
     280             :      example, they want to show the version or validate the produced
     281             :      binary without yet setting up the full TOML. */
     282             : 
     283           0 :   action_t * help_action = NULL;
     284           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     285           0 :     if( FD_UNLIKELY( ACTIONS[ i ]->is_help ) ) {
     286           0 :       help_action = ACTIONS[ i ];
     287           0 :       break;
     288           0 :     }
     289           0 :   }
     290             : 
     291           0 :   if( FD_UNLIKELY( !argc ) ) {
     292           0 :     help_action->fn( NULL, NULL );
     293           0 :     FD_LOG_WARNING(( "no subcommand specified, exiting" ));
     294           0 :     return 1;
     295           0 :   }
     296             : 
     297             :   /* We need to strip away (potentially leading) cmdline flags first,
     298             :      since the parser assumes the action is the leading argument */
     299           0 :   const char * opt_user_config_path = fd_env_strip_cmdline_cstr(
     300           0 :     &argc,
     301           0 :     &argv,
     302           0 :     "--config",
     303           0 :     "FIREDANCER_CONFIG_TOML",
     304           0 :     NULL );
     305             : 
     306           0 :   action_t * action = NULL;
     307           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     308           0 :     if( FD_UNLIKELY( !strcmp( argv[ 0 ], ACTIONS[ i ]->name ) ||
     309           0 :                      (!strcmp( argv[ 0 ], "--version" ) && !strcmp( "version", ACTIONS[ i ]->name )) ||
     310           0 :                      ((!strcmp( argv[ 0 ], "--help" ) || !strcmp( argv[ 0 ], "-h" )) && !strcmp( "help", ACTIONS[ i ]->name ))
     311           0 :     ) ) {
     312           0 :       action = ACTIONS[ i ];
     313           0 :       if( FD_UNLIKELY( action->is_immediate ) ) {
     314           0 :         action->fn( NULL, NULL );
     315           0 :         return 0;
     316           0 :       }
     317           0 :       break;
     318           0 :     }
     319           0 :   }
     320             : 
     321           0 :   if( FD_UNLIKELY( action ) ) {
     322           0 :     int help_argc = argc-1; char ** help_argv = argv+1;
     323           0 :     if( FD_UNLIKELY( fd_env_strip_cmdline_contains( &help_argc, &help_argv, "--help" ) || fd_env_strip_cmdline_contains( &help_argc, &help_argv, "-h" ) ) ) {
     324           0 :       fd_action_help_print( action );
     325           0 :       return 0;
     326           0 :     }
     327           0 :   }
     328             : 
     329           0 :   int is_local_cluster = action ? action->is_local_cluster : 0;
     330           0 :   int no_topo          = action ? action->no_topo          : 0;
     331           0 :   int load_topo = fd_main_init( &argc, &argv, &config, opt_user_config_path, is_local_cluster, no_topo, NULL, configs, 0 /* dev */ );
     332           0 :   if( FD_LIKELY( load_topo && action ) ) fd_cstr_ncpy( config.action, action->name, sizeof( config.action ) );
     333           0 :   if( FD_LIKELY( load_topo ) ) topo_init( &config );
     334             : 
     335           0 :   if( FD_UNLIKELY( !action ) ) {
     336           0 :     help_action->fn( NULL, NULL );
     337           0 :     FD_LOG_ERR(( "unknown subcommand `%s`", argv[ 0 ] ));
     338           0 :   }
     339             : 
     340           0 :   if( FD_UNLIKELY( action->require_config && !opt_user_config_path ) ) FD_LOG_ERR(( "missing required `--config` argument" ));
     341             : 
     342           0 :   argc--; argv++;
     343             : 
     344           0 :   args_t args = {0};
     345           0 :   if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
     346           0 :   if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
     347             : 
     348           0 :   if( FD_LIKELY( action->perm ) ) {
     349           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 ) ) );
     350             : 
     351           0 :     action->perm( &args, chk, &config );
     352             : 
     353           0 :     ulong err_cnt = fd_cap_chk_err_cnt( chk );
     354           0 :     if( FD_UNLIKELY( err_cnt ) ) {
     355           0 :       for( ulong i=0UL; i<err_cnt; i++ ) FD_LOG_WARNING(( "%s", fd_cap_chk_err( chk, i ) ));
     356             : 
     357           0 :       if( FD_LIKELY( action->permission_err ) ) FD_LOG_ERR(( action->permission_err, action->name ));
     358           0 :       else                                      FD_LOG_ERR(( "insufficient permissions to execute command `%s`", action->name ));
     359           0 :     }
     360           0 :   }
     361             : 
     362           0 :   action->fn( &args, &config );
     363             : 
     364           0 :   return 0;
     365           0 : }

Generated by: LCOV version 1.14