LCOV - code coverage report
Current view: top level - app/shared/boot - fd_boot.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 250 0.0 %
Date: 2025-12-07 04:58:33 Functions: 0 8 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             : extern int * fd_log_private_shared_lock;
      18             : 
      19             : fd_topo_run_tile_t
      20           0 : fdctl_tile_run( fd_topo_tile_t const * tile ) {
      21           0 :   for( ulong i=0UL; TILES[ i ]; i++ ) {
      22           0 :     if( !strcmp( tile->name, TILES[ i ]->name ) ) return *TILES[ i ];
      23           0 :   }
      24           0 :   FD_LOG_ERR(( "tile `%s` not found", tile->name ));
      25           0 :   return (fd_topo_run_tile_t){0};
      26           0 : }
      27             : 
      28             : static void
      29             : copy_config_from_fd( int        config_fd,
      30           0 :                      config_t * config ) {
      31           0 :   uchar * bytes = mmap( NULL, sizeof( config_t ), PROT_READ, MAP_PRIVATE, config_fd, 0 );
      32           0 :   if( FD_UNLIKELY( bytes == MAP_FAILED ) ) FD_LOG_ERR(( "mmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      33           0 :   fd_memcpy( config, bytes, sizeof( config_t ) );
      34           0 :   if( FD_UNLIKELY( munmap( bytes, sizeof( config_t ) ) ) ) FD_LOG_ERR(( "munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      35           0 :   if( FD_UNLIKELY( close( config_fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      36           0 : }
      37             : 
      38             : static int *
      39           0 : map_log_memfd( int log_memfd ) {
      40           0 :   void * shmem = mmap( NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, log_memfd, (off_t)0 );
      41           0 :   if( FD_UNLIKELY( shmem==MAP_FAILED ) ) {
      42           0 :     FD_LOG_ERR(( "mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,memfd,(off_t)0) (%i-%s); ", errno, fd_io_strerror( errno ) ));
      43           0 :   } else {
      44           0 :     if( FD_UNLIKELY( mlock( shmem, 4096 ) ) ) {
      45           0 :       FD_LOG_ERR(( "mlock(%p,4096) (%i-%s); unable to lock log file shared lock in memory\n", shmem, errno, fd_io_strerror( errno ) ));
      46           0 :     }
      47           0 :   }
      48           0 :   return shmem;
      49           0 : }
      50             : 
      51             : /* Try to allocate an anonymous page of memory in a file descriptor
      52             :    (memfd) for fd_log_private_shared_lock such that the log can strictly
      53             :    sequence messages written by clones of the caller made after the
      54             :    caller has finished booting the log.  Must be a file descriptor so
      55             :    we can pass it through `execve` calls. */
      56             : static int
      57           0 : init_log_memfd( void ) {
      58           0 :   int memfd = memfd_create( "fd_log_lock_page", 0U );
      59           0 :   if( FD_UNLIKELY( -1==memfd) ) FD_LOG_ERR(( "memfd_create(\"fd_log_lock_page\",0) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      60           0 :   if( FD_UNLIKELY( -1==ftruncate( memfd, 4096 ) ) ) FD_LOG_ERR(( "ftruncate(memfd,4096) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      61           0 :   return memfd;
      62           0 : }
      63             : 
      64             : static int
      65           0 : should_colorize( void ) {
      66           0 :   char const * cstr = fd_env_strip_cmdline_cstr( NULL, NULL, NULL, "COLORTERM", NULL );
      67           0 :   if( cstr && !strcmp( cstr, "truecolor" ) ) return 1;
      68             : 
      69           0 :   cstr = fd_env_strip_cmdline_cstr( NULL, NULL, NULL, "TERM", NULL );
      70           0 :   if( cstr && strstr( cstr, "256color" ) ) return 1;
      71           0 :   return 0;
      72           0 : }
      73             : 
      74             : static void
      75             : determine_override_config( int *                      pargc,
      76             :                            char ***                   pargv,
      77             :                            fd_config_file_t * const * configs,
      78             :                            char const **              override_config,
      79             :                            char const **              override_config_path,
      80           0 :                            ulong *                    override_config_sz ) {
      81           0 :   int testnet = fd_env_strip_cmdline_contains( pargc, pargv, "--testnet" );
      82           0 :   if( FD_UNLIKELY( testnet ) ) {
      83           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      84           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "testnet" ) ) ) {
      85           0 :         *override_config = (char const *)configs[ i ]->data;
      86           0 :         *override_config_path = configs[ i ]->name;
      87           0 :         *override_config_sz = configs[ i ]->data_sz;
      88           0 :         return;
      89           0 :       }
      90           0 :     }
      91             : 
      92           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no testnet config found" ));
      93           0 :   }
      94             : 
      95           0 :   int devnet = fd_env_strip_cmdline_contains( pargc, pargv, "--devnet" );
      96           0 :   if( FD_UNLIKELY( devnet ) ) {
      97           0 :     if( FD_UNLIKELY( testnet ) ) FD_LOG_ERR(( "cannot specify both --testnet and --devnet" ));
      98           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
      99           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "devnet" ) ) ) {
     100           0 :         *override_config = (char const *)configs[ i ]->data;
     101           0 :         *override_config_path = configs[ i ]->name;
     102           0 :         *override_config_sz = configs[ i ]->data_sz;
     103           0 :         return;
     104           0 :       }
     105           0 :     }
     106             : 
     107           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no devnet config found" ));
     108           0 :   }
     109             : 
     110           0 :   int mainnet = fd_env_strip_cmdline_contains( pargc, pargv, "--mainnet" );
     111           0 :   if( FD_UNLIKELY( mainnet ) ) {
     112           0 :     if( FD_UNLIKELY( testnet || devnet ) ) FD_LOG_ERR(( "cannot specify both --testnet or --devnet and --mainnet" ));
     113           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     114           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "mainnet" ) ) ) {
     115           0 :         *override_config = (char const *)configs[ i ]->data;
     116           0 :         *override_config_path = configs[ i ]->name;
     117           0 :         *override_config_sz = configs[ i ]->data_sz;
     118           0 :         return;
     119           0 :       }
     120           0 :     }
     121             : 
     122           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no mainnet config found" ));
     123           0 :   }
     124             : 
     125           0 :   int testnet_jito = fd_env_strip_cmdline_contains( pargc, pargv, "--testnet-jito" );
     126           0 :   if( FD_UNLIKELY( testnet_jito ) ) {
     127           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     128           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "testnet-jito" ) ) ) {
     129           0 :         *override_config = (char const *)configs[ i ]->data;
     130           0 :         *override_config_path = configs[ i ]->name;
     131           0 :         *override_config_sz = configs[ i ]->data_sz;
     132           0 :         return;
     133           0 :       }
     134           0 :     }
     135             : 
     136           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no testnet-jito config found" ));
     137           0 :   }
     138             : 
     139           0 :   int mainnet_jito = fd_env_strip_cmdline_contains( pargc, pargv, "--mainnet-jito" );
     140           0 :   if( FD_UNLIKELY( mainnet_jito ) ) {
     141           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     142           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "mainnet-jito" ) ) ) {
     143           0 :         *override_config = (char const *)configs[ i ]->data;
     144           0 :         *override_config_path = configs[ i ]->name;
     145           0 :         *override_config_sz = configs[ i ]->data_sz;
     146           0 :         return;
     147           0 :       }
     148           0 :     }
     149             : 
     150           0 :     if( FD_UNLIKELY( !*override_config ) ) FD_LOG_ERR(( "no mainnet-jito config found" ));
     151           0 :   }
     152           0 : }
     153             : 
     154             : void
     155             : fd_main_init( int *                      pargc,
     156             :               char ***                   pargv,
     157             :               config_t   *               config,
     158             :               const char *               opt_user_config_path,
     159             :               int                        is_firedancer,
     160             :               int                        is_local_cluster,
     161             :               char const *               log_path,
     162             :               fd_config_file_t * const * configs,
     163           0 :               void (* topo_init )( config_t * config ) ) {
     164           0 :   fd_log_enable_unclean_exit(); /* Don't call atexit handlers on FD_LOG_ERR */
     165           0 :   fd_log_level_core_set( 5 ); /* Don't dump core for FD_LOG_ERR during boot */
     166           0 :   fd_log_colorize_set( should_colorize() ); /* Colorize during boot until we can determine from config */
     167           0 :   fd_log_level_stderr_set( 2 ); /* Only NOTICE and above will be logged during boot until fd_log is initialized */
     168             : 
     169           0 :   int config_fd = fd_env_strip_cmdline_int( pargc, pargv, "--config-fd", NULL, -1 );
     170             : 
     171           0 :   fd_memset( config, 0, sizeof( config_t ) );
     172           0 :   char * thread = "";
     173           0 :   if( FD_UNLIKELY( config_fd >= 0 ) ) {
     174           0 :     copy_config_from_fd( config_fd, config );
     175             :     /* tick_per_ns needs to be synchronized across processes so that
     176             :        they can coordinate on metrics measurement. */
     177           0 :     fd_tempo_set_tick_per_ns( config->tick_per_ns_mu, config->tick_per_ns_sigma );
     178           0 :   } else {
     179           0 :     char * user_config = NULL;
     180           0 :     ulong user_config_sz = 0UL;
     181           0 :     if( FD_LIKELY( opt_user_config_path ) ) {
     182           0 :       user_config = fd_file_util_read_all( opt_user_config_path, &user_config_sz );
     183           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 ) ));
     184           0 :     }
     185             : 
     186           0 :     int netns = fd_env_strip_cmdline_contains( pargc, pargv, "--netns" );
     187             : 
     188           0 :     char const * default_config = NULL;
     189           0 :     ulong default_config_sz = 0UL;
     190           0 :     for( ulong i=0UL; configs[ i ]; i++ ) {
     191           0 :       if( FD_UNLIKELY( !strcmp( configs[ i ]->name, "default" ) ) ) {
     192           0 :         default_config = (char const *)configs[ i ]->data;
     193           0 :         default_config_sz = configs[ i ]->data_sz;
     194           0 :         break;
     195           0 :       }
     196           0 :     }
     197           0 :     if( FD_UNLIKELY( !default_config ) ) FD_LOG_ERR(( "no default config found" ));
     198             : 
     199           0 :     char const * override_config = NULL;
     200           0 :     char const * override_config_path = NULL;
     201           0 :     ulong override_config_sz = 0UL;
     202           0 :     determine_override_config( pargc, pargv, configs,
     203           0 :                                &override_config, &override_config_path, &override_config_sz );
     204             : 
     205           0 :     fd_config_load( is_firedancer, netns, 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 );
     206           0 :     topo_init( config );
     207             : 
     208           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 ) ));
     209             : 
     210           0 :     config->log.lock_fd = init_log_memfd();
     211           0 :     config->log.log_fd  = -1;
     212           0 :     thread = "main";
     213           0 :     if( FD_UNLIKELY( log_path ) )
     214           0 :       strncpy( config->log.path, log_path, sizeof( config->log.path ) - 1 );
     215           0 :   }
     216             : 
     217           0 :   char * shmem_args[ 3 ];
     218             :   /* pass in --shmem-path value from the config */
     219           0 :   shmem_args[ 0 ] = "--shmem-path";
     220           0 :   shmem_args[ 1 ] = config->hugetlbfs.mount_path;
     221           0 :   shmem_args[ 2 ] = NULL;
     222           0 :   char ** argv = shmem_args;
     223           0 :   int     argc = 2;
     224             : 
     225           0 :   int * log_lock = map_log_memfd( config->log.lock_fd );
     226           0 :   ulong pid = fd_sandbox_getpid(); /* Need to read /proc since we might be in a PID namespace now */;
     227             : 
     228           0 :   log_path = config->log.path;
     229           0 :   if( FD_LIKELY( config->log.path[ 0 ]=='\0' ) ) log_path = NULL;
     230             : 
     231             :   /* Switch to the sandbox uid/gid for log file creation, so it's always
     232             :      owned by that user. */
     233             : 
     234           0 :   gid_t gid = getgid();
     235           0 :   uid_t uid = getuid();
     236           0 :   if( FD_LIKELY( !gid && setegid( config->gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     237           0 :   if( FD_LIKELY( !uid && seteuid( config->uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     238             : 
     239           0 :   int boot_silent = config_fd>=0;
     240           0 :   fd_log_private_boot_custom( log_lock,
     241           0 :                               0UL,
     242           0 :                               config->name,
     243           0 :                               0UL,    /* Thread ID will be initialized later */
     244           0 :                               thread, /* Thread will be initialized later */
     245           0 :                               0UL,
     246           0 :                               config->hostname,
     247           0 :                               fd_log_private_cpu_id_default(),
     248           0 :                               NULL,
     249           0 :                               pid,
     250           0 :                               NULL,
     251           0 :                               pid,
     252           0 :                               config->uid,
     253           0 :                               config->user,
     254           0 :                               1,
     255           0 :                               config->log.colorize1,
     256           0 :                               boot_silent ? 2 : config->log.level_logfile1,
     257           0 :                               boot_silent ? 2 : config->log.level_stderr1,
     258           0 :                               boot_silent ? 3 : config->log.level_flush1,
     259           0 :                               5,
     260           0 :                               config->log.log_fd,
     261           0 :                               log_path );
     262             : 
     263           0 :   if( FD_UNLIKELY( seteuid( uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     264           0 :   if( FD_UNLIKELY( setegid( gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     265             : 
     266           0 :   config->log.log_fd = fd_log_private_logfile_fd();
     267           0 :   fd_shmem_private_boot( &argc, &argv );
     268           0 :   fd_tile_private_boot( 0, NULL );
     269             : 
     270           0 :   fd_log_level_logfile_set( config->log.level_logfile1 );
     271           0 :   fd_log_level_stderr_set( config->log.level_stderr1 );
     272           0 :   fd_log_level_flush_set( config->log.level_flush1 );
     273           0 : }
     274             : 
     275             : static config_t config;
     276             : 
     277             : int
     278             : fd_main( int                        argc,
     279             :          char **                    _argv,
     280             :          int                        is_firedancer,
     281             :          fd_config_file_t * const * configs,
     282           0 :          void (* topo_init )( config_t * config ) ) {
     283           0 :   char ** argv = _argv;
     284           0 :   argc--; argv++;
     285             : 
     286             :   /* Short circuit evaluating help and version commands so that we don't
     287             :      need to load and evaluate the entire config file to run them.
     288             :      This is useful for some operators in CI environments where, for
     289             :      example, they want to show the version or validate the produced
     290             :      binary without yet setting up the full TOML. */
     291             : 
     292           0 :   action_t * help_action = NULL;
     293           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     294           0 :     if( FD_UNLIKELY( ACTIONS[ i ]->is_help ) ) {
     295           0 :       help_action = ACTIONS[ i ];
     296           0 :       break;
     297           0 :     }
     298           0 :   }
     299             : 
     300           0 :   if( FD_UNLIKELY( !argc ) ) {
     301           0 :     help_action->fn( NULL, NULL );
     302           0 :     FD_LOG_WARNING(( "no subcommand specified, exiting" ));
     303           0 :     return 1;
     304           0 :   }
     305             : 
     306             :   /* We need to strip away (potentially leading) cmdline flags first,
     307             :      since the parser assumes the action is the leading argument */
     308           0 :   const char * opt_user_config_path = fd_env_strip_cmdline_cstr(
     309           0 :     &argc,
     310           0 :     &argv,
     311           0 :     "--config",
     312           0 :     "FIREDANCER_CONFIG_TOML",
     313           0 :     NULL );
     314             : 
     315           0 :   action_t * action = NULL;
     316           0 :   for( ulong i=0UL; ACTIONS[ i ]; i++ ) {
     317           0 :     if( FD_UNLIKELY( !strcmp( argv[ 0 ], ACTIONS[ i ]->name ) ||
     318           0 :                      (!strcmp( argv[ 0 ], "--version" ) && !strcmp( "version", ACTIONS[ i ]->name )) ||
     319           0 :                      (!strcmp( argv[ 0 ], "--help" ) && !strcmp( "help", ACTIONS[ i ]->name ))
     320           0 :     ) ) {
     321           0 :       action = ACTIONS[ i ];
     322           0 :       if( FD_UNLIKELY( action->is_immediate ) ) {
     323           0 :         action->fn( NULL, NULL );
     324           0 :         return 0;
     325           0 :       }
     326           0 :       break;
     327           0 :     }
     328           0 :   }
     329             : 
     330           0 :   int is_local_cluster = action ? action->is_local_cluster : 0;
     331           0 :   fd_main_init( &argc, &argv, &config, opt_user_config_path, is_firedancer, is_local_cluster, NULL, configs, topo_init );
     332             : 
     333           0 :   if( FD_UNLIKELY( !action ) ) {
     334           0 :     help_action->fn( NULL, NULL );
     335           0 :     FD_LOG_ERR(( "unknown subcommand `%s`", argv[ 0 ] ));
     336           0 :   }
     337             : 
     338           0 :   if( FD_UNLIKELY( action->require_config && !opt_user_config_path ) ) FD_LOG_ERR(( "missing required `--config` argument" ));
     339             : 
     340           0 :   argc--; argv++;
     341             : 
     342           0 :   args_t args = {0};
     343           0 :   if( FD_LIKELY( action->args ) ) action->args( &argc, &argv, &args );
     344           0 :   if( FD_UNLIKELY( argc ) ) FD_LOG_ERR(( "unknown argument `%s`", argv[ 0 ] ));
     345             : 
     346           0 :   if( FD_LIKELY( action->perm ) ) {
     347           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 ) ) );
     348             : 
     349           0 :     action->perm( &args, chk, &config );
     350             : 
     351           0 :     ulong err_cnt = fd_cap_chk_err_cnt( chk );
     352           0 :     if( FD_UNLIKELY( err_cnt ) ) {
     353           0 :       for( ulong i=0UL; i<err_cnt; i++ ) FD_LOG_WARNING(( "%s", fd_cap_chk_err( chk, i ) ));
     354             : 
     355           0 :       if( FD_LIKELY( action->permission_err ) ) FD_LOG_ERR(( action->permission_err, action->name ));
     356           0 :       else                                      FD_LOG_ERR(( "insufficient permissions to execute command `%s`", action->name ));
     357           0 :     }
     358           0 :   }
     359             : 
     360           0 :   action->fn( &args, &config );
     361             : 
     362           0 :   return 0;
     363           0 : }

Generated by: LCOV version 1.14