LCOV - code coverage report
Current view: top level - app/shared/boot - fd_boot.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 4 226 1.8 %
Date: 2025-09-19 04:41:14 Functions: 1 8 12.5 %

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

Generated by: LCOV version 1.14