LCOV - code coverage report
Current view: top level - app/shared/boot - fd_boot.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 223 0.0 %
Date: 2026-04-01 06:30:45 Functions: 0 5 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             : int
     117             : fd_main_init( int *                      pargc,
     118             :               char ***                   pargv,
     119             :               config_t   *               config,
     120             :               const char *               opt_user_config_path,
     121             :               int                        is_firedancer,
     122             :               int                        is_local_cluster,
     123             :               char const *               log_path,
     124           0 :               fd_config_file_t * const * configs ) {
     125           0 :   fd_log_enable_unclean_exit(); /* Don't call atexit handlers on FD_LOG_ERR */
     126           0 :   fd_log_level_core_set( 5 ); /* Don't dump core for FD_LOG_ERR during boot */
     127           0 :   fd_log_colorize_set( fd_log_should_colorize() ); /* Colorize during boot until we can determine from config */
     128           0 :   fd_log_level_stderr_set( 2 ); /* Only NOTICE and above will be logged during boot until fd_log is initialized */
     129             : 
     130           0 :   int config_fd = fd_env_strip_cmdline_int( pargc, pargv, "--config-fd", NULL, -1 );
     131             : 
     132           0 :   fd_memset( config, 0, sizeof( config_t ) );
     133           0 :   char * thread = "";
     134           0 :   if( FD_UNLIKELY( config_fd >= 0 ) ) {
     135           0 :     copy_config_from_fd( config_fd, config );
     136             :     /* tick_per_ns needs to be synchronized across processes so that
     137             :        they can coordinate on metrics measurement. */
     138           0 :     fd_tempo_set_tick_per_ns( config->tick_per_ns_mu, config->tick_per_ns_sigma );
     139           0 :   } else {
     140           0 :     char * user_config = NULL;
     141           0 :     ulong user_config_sz = 0UL;
     142           0 :     if( FD_LIKELY( opt_user_config_path ) ) {
     143           0 :       user_config = fd_file_util_read_all( opt_user_config_path, &user_config_sz );
     144           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 ) ));
     145           0 :     }
     146             : 
     147           0 :     char const * default_config = NULL;
     148           0 :     ulong default_config_sz = 0UL;
     149           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     150           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "default" ) ) ) {
     151           0 :         default_config = (char const *)configs[ i ]->data;
     152           0 :         default_config_sz = configs[ i ]->data_sz;
     153           0 :         break;
     154           0 :       }
     155           0 :     }
     156           0 :     if( FD_UNLIKELY( !default_config ) ) FD_LOG_ERR(( "no default config found" ));
     157             : 
     158           0 :     char const * override_config = NULL;
     159           0 :     char const * override_config_path = NULL;
     160           0 :     ulong override_config_sz = 0UL;
     161           0 :     determine_override_config( pargc, pargv, configs,
     162           0 :                                &override_config, &override_config_path, &override_config_sz );
     163             : 
     164           0 :     fd_config_load( is_firedancer, 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 );
     165             : 
     166           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 ) ));
     167             : 
     168           0 :     config->log.log_fd  = -1;
     169           0 :     thread = "main";
     170           0 :     if( FD_UNLIKELY( log_path ) )
     171           0 :       strncpy( config->log.path, log_path, sizeof( config->log.path ) - 1 );
     172           0 :   }
     173             : 
     174           0 :   char * shmem_args[ 3 ];
     175             :   /* pass in --shmem-path value from the config */
     176           0 :   shmem_args[ 0 ] = "--shmem-path";
     177           0 :   shmem_args[ 1 ] = config->hugetlbfs.mount_path;
     178           0 :   shmem_args[ 2 ] = NULL;
     179           0 :   char ** argv = shmem_args;
     180           0 :   int     argc = 2;
     181             : 
     182           0 :   ulong pid = fd_sandbox_getpid(); /* Need to read /proc since we might be in a PID namespace now */;
     183             : 
     184           0 :   log_path = config->log.path;
     185           0 :   if( FD_LIKELY( config->log.path[ 0 ]=='\0' ) ) log_path = NULL;
     186             : 
     187             :   /* Switch to the sandbox uid/gid for log file creation, so it's always
     188             :      owned by that user. */
     189             : 
     190           0 :   gid_t gid = getgid();
     191           0 :   uid_t uid = getuid();
     192           0 :   if( FD_LIKELY( !gid && setegid( config->gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     193           0 :   if( FD_LIKELY( !uid && seteuid( config->uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     194             : 
     195           0 :   int boot_silent = config_fd>=0;
     196           0 :   fd_log_private_boot_custom( 0UL,
     197           0 :                               config->name,
     198           0 :                               0UL,    /* Thread ID will be initialized later */
     199           0 :                               thread, /* Thread will be initialized later */
     200           0 :                               0UL,
     201           0 :                               config->hostname,
     202           0 :                               fd_log_private_cpu_id_default(),
     203           0 :                               NULL,
     204           0 :                               pid,
     205           0 :                               NULL,
     206           0 :                               pid,
     207           0 :                               config->uid,
     208           0 :                               config->user,
     209           0 :                               1,
     210           0 :                               config->log.colorize1,
     211           0 :                               boot_silent ? 2 : config->log.level_logfile1,
     212           0 :                               boot_silent ? 2 : config->log.level_stderr1,
     213           0 :                               boot_silent ? 3 : config->log.level_flush1,
     214           0 :                               5,
     215           0 :                               config->log.log_fd,
     216           0 :                               log_path );
     217             : 
     218           0 :   if( FD_UNLIKELY( seteuid( uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     219           0 :   if( FD_UNLIKELY( setegid( gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     220             : 
     221           0 :   config->log.log_fd = fd_log_private_logfile_fd();
     222           0 :   fd_shmem_private_boot( &argc, &argv );
     223           0 :   fd_tile_private_boot( 0, NULL );
     224             : 
     225           0 :   fd_log_level_logfile_set( config->log.level_logfile1 );
     226           0 :   fd_log_level_stderr_set( config->log.level_stderr1 );
     227           0 :   fd_log_level_flush_set( config->log.level_flush1 );
     228             : 
     229           0 :   return config_fd<0;
     230           0 : }
     231             : 
     232             : static config_t config;
     233             : 
     234             : int
     235             : fd_main( int                        argc,
     236             :          char **                    _argv,
     237             :          int                        is_firedancer,
     238             :          fd_config_file_t * const * configs,
     239           0 :          void (* topo_init )( config_t * config ) ) {
     240           0 :   char ** argv = _argv;
     241           0 :   argc--; argv++;
     242             : 
     243             :   /* Short circuit evaluating help and version commands so that we don't
     244             :      need to load and evaluate the entire config file to run them.
     245             :      This is useful for some operators in CI environments where, for
     246             :      example, they want to show the version or validate the produced
     247             :      binary without yet setting up the full TOML. */
     248             : 
     249           0 :   action_t * help_action = NULL;
     250           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     251           0 :     if( FD_UNLIKELY( ACTIONS[ i ]->is_help ) ) {
     252           0 :       help_action = ACTIONS[ i ];
     253           0 :       break;
     254           0 :     }
     255           0 :   }
     256             : 
     257           0 :   if( FD_UNLIKELY( !argc ) ) {
     258           0 :     help_action->fn( NULL, NULL );
     259           0 :     FD_LOG_WARNING(( "no subcommand specified, exiting" ));
     260           0 :     return 1;
     261           0 :   }
     262             : 
     263             :   /* We need to strip away (potentially leading) cmdline flags first,
     264             :      since the parser assumes the action is the leading argument */
     265           0 :   const char * opt_user_config_path = fd_env_strip_cmdline_cstr(
     266           0 :     &argc,
     267           0 :     &argv,
     268           0 :     "--config",
     269           0 :     "FIREDANCER_CONFIG_TOML",
     270           0 :     NULL );
     271             : 
     272           0 :   action_t * action = NULL;
     273           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     274           0 :     if( FD_UNLIKELY( !strcmp( argv[ 0 ], ACTIONS[ i ]->name ) ||
     275           0 :                      (!strcmp( argv[ 0 ], "--version" ) && !strcmp( "version", ACTIONS[ i ]->name )) ||
     276           0 :                      (!strcmp( argv[ 0 ], "--help" ) && !strcmp( "help", ACTIONS[ i ]->name ))
     277           0 :     ) ) {
     278           0 :       action = ACTIONS[ i ];
     279           0 :       if( FD_UNLIKELY( action->is_immediate ) ) {
     280           0 :         action->fn( NULL, NULL );
     281           0 :         return 0;
     282           0 :       }
     283           0 :       break;
     284           0 :     }
     285           0 :   }
     286             : 
     287           0 :   int is_local_cluster = action ? action->is_local_cluster : 0;
     288           0 :   int load_topo = fd_main_init( &argc, &argv, &config, opt_user_config_path, is_firedancer, is_local_cluster, NULL, configs );
     289           0 :   if( FD_LIKELY( load_topo ) ) topo_init( &config );
     290             : 
     291           0 :   if( FD_UNLIKELY( !action ) ) {
     292           0 :     help_action->fn( NULL, NULL );
     293           0 :     FD_LOG_ERR(( "unknown subcommand `%s`", argv[ 0 ] ));
     294           0 :   }
     295             : 
     296           0 :   if( FD_UNLIKELY( action->require_config && !opt_user_config_path ) ) FD_LOG_ERR(( "missing required `--config` argument" ));
     297             : 
     298           0 :   argc--; argv++;
     299             : 
     300           0 :   args_t args = {0};
     301           0 :   if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
     302           0 :   if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
     303             : 
     304           0 :   if( FD_LIKELY( action->perm ) ) {
     305           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 ) ) );
     306             : 
     307           0 :     action->perm( &args, chk, &config );
     308             : 
     309           0 :     ulong err_cnt = fd_cap_chk_err_cnt( chk );
     310           0 :     if( FD_UNLIKELY( err_cnt ) ) {
     311           0 :       for( ulong i=0UL; i<err_cnt; i++ ) FD_LOG_WARNING(( "%s", fd_cap_chk_err( chk, i ) ));
     312             : 
     313           0 :       if( FD_LIKELY( action->permission_err ) ) FD_LOG_ERR(( action->permission_err, action->name ));
     314           0 :       else                                      FD_LOG_ERR(( "insufficient permissions to execute command `%s`", action->name ));
     315           0 :     }
     316           0 :   }
     317             : 
     318           0 :   action->fn( &args, &config );
     319             : 
     320           0 :   return 0;
     321           0 : }

Generated by: LCOV version 1.14