LCOV - code coverage report
Current view: top level - app/fdctl/configure - configure.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 164 0.0 %
Date: 2025-01-08 12:08:44 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #include "configure.h"
       2             : 
       3             : #include <sys/stat.h>
       4             : 
       5             : void
       6             : configure_cmd_args( int *    pargc,
       7             :                     char *** pargv,
       8           0 :                     args_t * args) {
       9           0 :   char * usage = "usage: configure <init|check|fini> <stage>...";
      10           0 :   if( FD_UNLIKELY( *pargc < 2 ) ) FD_LOG_ERR(( "%s", usage ));
      11             : 
      12           0 :   if(      FD_LIKELY( !strcmp( *pargv[ 0 ], "check" ) ) ) args->configure.command = CONFIGURE_CMD_CHECK;
      13           0 :   else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "init"  ) ) ) args->configure.command = CONFIGURE_CMD_INIT;
      14           0 :   else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "fini"  ) ) ) args->configure.command = CONFIGURE_CMD_FINI;
      15           0 :   else FD_LOG_ERR(( "unrecognized command `%s`, %s", *pargv[0], usage ));
      16             : 
      17           0 :   (*pargc)--;
      18           0 :   (*pargv)++;
      19             : 
      20           0 :   for( int i=0; i<*pargc; i++ ) {
      21           0 :     if( FD_UNLIKELY( !strcmp( (*pargv)[ i ], "all" ) ) ) {
      22           0 :       (*pargc) -= i + 1;
      23           0 :       (*pargv) += i + 1;
      24           0 :       for( int j=0; j<CONFIGURE_STAGE_COUNT; j++) args->configure.stages[ j ] = STAGES[ j ];
      25           0 :       return;
      26           0 :     }
      27           0 :   }
      28             : 
      29           0 :   if( FD_UNLIKELY( *pargc >= CONFIGURE_STAGE_COUNT ) ) FD_LOG_ERR(( "too many stages specified" ));
      30             : 
      31           0 :   ulong nstage = 0;
      32           0 :   while( *pargc ) {
      33           0 :     int found = 0;
      34           0 :     for( configure_stage_t ** stage = STAGES; *stage; stage++ ) {
      35           0 :       if( FD_UNLIKELY( !strcmp( (*pargv)[0], (*stage)->name ) ) ) {
      36           0 :         args->configure.stages[ nstage++ ] = *stage;
      37           0 :         found = 1;
      38           0 :         break;
      39           0 :       }
      40           0 :     }
      41             : 
      42           0 :     if( FD_UNLIKELY( !found ) ) FD_LOG_ERR(( "unknown configure stage: %s", (*pargv)[0] ));
      43             : 
      44           0 :     (*pargc)--;
      45           0 :     (*pargv)++;
      46           0 :   }
      47           0 :   return;
      48           0 : }
      49             : 
      50             : void
      51             : configure_cmd_perm( args_t *         args,
      52             :                     fd_caps_ctx_t *  caps,
      53           0 :                     config_t * const config ) {
      54           0 :   for( configure_stage_t ** stage = args->configure.stages; *stage; stage++ ) {
      55           0 :     switch( args->configure.command ) {
      56           0 :       case CONFIGURE_CMD_INIT: {
      57           0 :         int enabled = !(*stage)->enabled || (*stage)->enabled( config );
      58           0 :         if( FD_LIKELY( enabled && (*stage)->check( config ).result != CONFIGURE_OK ) )
      59           0 :           if( FD_LIKELY( (*stage)->init_perm ) ) (*stage)->init_perm( caps, config );
      60           0 :         break;
      61           0 :       }
      62           0 :       case CONFIGURE_CMD_CHECK:
      63           0 :         break;
      64           0 :       case CONFIGURE_CMD_FINI: {
      65           0 :         int enabled = !(*stage)->enabled || (*stage)->enabled( config );
      66           0 :         if( FD_LIKELY( enabled && (*stage)->check( config ).result != CONFIGURE_NOT_CONFIGURED ) )
      67           0 :           if( FD_LIKELY( (*stage)->fini_perm ) ) (*stage)->fini_perm( caps, config );
      68           0 :         break;
      69           0 :       }
      70           0 :     }
      71           0 :   }
      72           0 : }
      73             : 
      74             : static int
      75             : configure_stage( configure_stage_t * stage,
      76             :                  configure_cmd_t     command,
      77           0 :                  config_t * const    config ) {
      78           0 :   if( FD_UNLIKELY( stage->enabled && !stage->enabled( config ) ) ) {
      79           0 :     FD_LOG_NOTICE(( "%s ... skipping .. not enabled", stage->name ));
      80           0 :     return 0;
      81           0 :   }
      82             : 
      83           0 :   switch( command ) {
      84           0 :     case CONFIGURE_CMD_INIT: {
      85           0 :       configure_result_t result = stage->check( config );
      86           0 :       if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) )
      87           0 :         FD_LOG_NOTICE(( "%s ... unconfigured ... %s", stage->name, result.message ));
      88           0 :       else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED ) ) {
      89           0 :         if( FD_LIKELY( stage->fini ) ) {
      90           0 :           FD_LOG_NOTICE(( "%s ... undoing ... %s", stage->name, result.message ));
      91           0 :           stage->fini( config, 1 );
      92           0 :         } else if( FD_UNLIKELY( !stage->always_recreate ) ) {
      93           0 :           FD_LOG_ERR(( "%s ... does not support undo but was not valid ... %s", stage->name, result.message ));
      94           0 :         }
      95             : 
      96           0 :         result = stage->check( config );
      97           0 :         if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) )
      98           0 :           FD_LOG_ERR(( "%s ... clean was unable to get back to an unconfigured state ... %s", stage->name, result.message ));
      99           0 :       } else {
     100           0 :         FD_LOG_NOTICE(( "%s ... already valid", stage->name ));
     101           0 :         return 0;
     102           0 :       }
     103             : 
     104           0 :       FD_LOG_NOTICE(( "%s ... configuring", stage->name ));
     105           0 :       if( FD_LIKELY( stage->init ) ) stage->init( config );
     106             : 
     107           0 :       result = stage->check( config );
     108           0 :       if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) )
     109           0 :         FD_LOG_ERR(( "%s ... tried to initialize but didn't do anything ... %s", stage->name, result.message ));
     110           0 :       else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) )
     111           0 :         FD_LOG_ERR(( "%s ... tried to initialize but was still unconfigured ... %s", stage->name, result.message ));
     112           0 :       break;
     113           0 :     }
     114           0 :     case CONFIGURE_CMD_CHECK: {
     115           0 :       configure_result_t result = stage->check( config );
     116           0 :       if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) ) {
     117           0 :         FD_LOG_WARNING(( "%s ... not configured ... %s", stage->name, result.message ));
     118           0 :         return 1;
     119           0 :       } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED ) ) {
     120           0 :         if( FD_UNLIKELY( !stage->always_recreate ) ) {
     121           0 :           FD_LOG_WARNING(( "%s ... invalid ... %s", stage->name, result.message ));
     122           0 :           return 1;
     123           0 :         } else {
     124           0 :           FD_LOG_NOTICE(( "%s ... not configured ... must always be recreated", stage->name ));
     125           0 :         }
     126           0 :       }
     127           0 :       break;
     128           0 :     }
     129           0 :     case CONFIGURE_CMD_FINI: {
     130           0 :       configure_result_t result = stage->check( config );
     131             : 
     132           0 :       if( FD_UNLIKELY( result.result == CONFIGURE_NOT_CONFIGURED ) ) {
     133           0 :         FD_LOG_NOTICE(( "%s ... not configured ... %s", stage->name, result.message ));
     134           0 :         return 0;
     135           0 :       } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate && !stage->fini ) ) {
     136           0 :         FD_LOG_ERR(( "%s ... not valid ... %s", stage->name, result.message ));
     137           0 :       }
     138             : 
     139           0 :       FD_LOG_NOTICE(( "%s ... finishing", stage->name ));
     140           0 :       if( FD_LIKELY( stage->fini ) ) stage->fini( config, 0 );
     141             : 
     142           0 :       result = stage->check( config );
     143           0 :       if( FD_UNLIKELY( result.result == CONFIGURE_OK && stage->init && stage->fini ) ) {
     144             :         /* if the step does nothing, it's fine if it's fully configured
     145             :             after being undone */
     146           0 :         FD_LOG_ERR(( "%s ... not undone", stage->name ));
     147           0 :       } else if( FD_UNLIKELY( result.result == CONFIGURE_PARTIALLY_CONFIGURED && !stage->always_recreate ) ) {
     148           0 :         FD_LOG_ERR(( "%s ... invalid ... %s", stage->name, result.message ));
     149           0 :       }
     150           0 :       break;
     151           0 :     }
     152           0 :   }
     153             : 
     154           0 :   return 0;
     155           0 : }
     156             : 
     157             : void
     158             : configure_cmd_fn( args_t *         args,
     159           0 :                   config_t * const config ) {
     160           0 :   int error = 0;
     161             : 
     162           0 :   if( FD_LIKELY( (configure_cmd_t)args->configure.command != CONFIGURE_CMD_FINI ) ) {
     163           0 :     for( configure_stage_t ** stage = args->configure.stages; *stage; stage++ ) {
     164           0 :       if( FD_UNLIKELY( configure_stage( *stage, (configure_cmd_t)args->configure.command, config ) ) ) error = 1;
     165           0 :     }
     166           0 :   } else {
     167           0 :     ulong i;
     168           0 :     for( i=0; args->configure.stages[ i ]; i++ ) ;
     169           0 :     if( FD_LIKELY( i > 0 ) ) {
     170           0 :       for( ulong j=0; j<i; j++ ) {
     171           0 :         if( FD_UNLIKELY( configure_stage( args->configure.stages[ i-1-j ], (configure_cmd_t)args->configure.command, config ) ) ) error = 1;
     172           0 :       }
     173           0 :     }
     174           0 :   }
     175             : 
     176             : 
     177           0 :   if( FD_UNLIKELY( error ) ) FD_LOG_ERR(( "failed to configure some stages" ));
     178           0 : }
     179             : 
     180             : static configure_result_t
     181             : check_path( const char * path,
     182             :             uint         expected_uid,
     183             :             uint         expected_gid,
     184             :             uint         expected_mode,
     185           0 :             int          expected_dir ) {
     186           0 :   struct stat st;
     187           0 :   if( FD_UNLIKELY( stat( path, &st ) ) ) {
     188           0 :     if( FD_LIKELY( errno == ENOENT ) ) PARTIALLY_CONFIGURED( "path `%s` does not exist", path );
     189           0 :     PARTIALLY_CONFIGURED( "failed to stat `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) );
     190           0 :   }
     191           0 :   if( FD_UNLIKELY( expected_dir && !S_ISDIR( st.st_mode ) ) )
     192           0 :     PARTIALLY_CONFIGURED( "path `%s` is a file, not a directory", path );
     193           0 :   if( FD_UNLIKELY( !expected_dir && S_ISDIR( st.st_mode ) ) )
     194           0 :     PARTIALLY_CONFIGURED( "path `%s` is a directory, not a file", path );
     195             : 
     196           0 :   if( FD_UNLIKELY( st.st_uid != expected_uid ) )
     197           0 :     PARTIALLY_CONFIGURED( "path `%s` has uid %u, expected %u", path, st.st_uid, expected_uid );
     198           0 :   if( FD_UNLIKELY( st.st_gid != expected_gid ) )
     199           0 :     PARTIALLY_CONFIGURED( "path `%s` has gid %u, expected %u", path, st.st_gid, expected_gid );
     200           0 :   if( FD_UNLIKELY( st.st_mode != expected_mode ) )
     201           0 :     PARTIALLY_CONFIGURED( "path `%s` has mode %o, expected %o", path, st.st_mode, expected_mode );
     202             : 
     203           0 :   CONFIGURE_OK();
     204           0 : }
     205             : 
     206             : configure_result_t
     207             : check_dir( const char * path,
     208             :            uint         uid,
     209             :            uint         gid,
     210           0 :            uint         mode ) {
     211           0 :   return check_path( path, uid, gid, mode, 1 );
     212           0 : }
     213             : 
     214             : configure_result_t
     215             : check_file( const char * path,
     216             :             uint         uid,
     217             :             uint         gid,
     218           0 :             uint         mode ) {
     219           0 :   return check_path( path, uid, gid, mode, 0 );
     220           0 : }

Generated by: LCOV version 1.14