LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp_io.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 118 144 81.9 %
Date: 2026-11-12 04:25:03 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "fd_wksp_private.h"
       2             : #include "../tpool/fd_tpool.h"
       3             : #include "../checkpt/fd_checkpt.h"
       4             : 
       5             : #include <stdio.h>
       6             : #include <errno.h>
       7             : #include <unistd.h>
       8             : #include <fcntl.h>
       9             : 
      10             : /* fd_wksp_private_checkpt_read reads up to the leading buf_max bytes at
      11             :    path into buf.  On success, returns 0 and *_buf_sz will contain the
      12             :    number of bytes read.  Returns a fd_io_strerror compatible error code
      13             :    on failure and *_buf_sz will be unchanged (buf might have been
      14             :    clobbered). */
      15             : 
      16             : static int
      17             : fd_wksp_private_checkpt_read( char const * path,       /* Assumes valid */
      18             :                               void *       buf,        /* Assumes valid */
      19             :                               ulong        buf_max,    /* Assumes buf_max>=12 */
      20         135 :                               ulong *      _buf_sz ) { /* Assumes non-NULL */
      21             : 
      22         135 :   int fd = open( path, O_RDONLY, (mode_t)0 );
      23         135 :   if( FD_UNLIKELY( fd==-1 ) ) return errno;
      24             : 
      25         135 :   int err = fd_io_read( fd, buf, 12UL, buf_max, _buf_sz );
      26             : 
      27         135 :   if( FD_UNLIKELY( close( fd ) ) )
      28           0 :     FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
      29             : 
      30         135 :   return err;
      31         135 : }
      32             : 
      33             : int
      34             : fd_wksp_preview( char const *        path,
      35         135 :                  fd_wksp_preview_t * _opt_preview ) {
      36             : 
      37             :   /* Check input args */
      38             : 
      39         135 :   if( FD_UNLIKELY( !path ) ) return FD_WKSP_ERR_INVAL;
      40             : 
      41         135 :   fd_wksp_preview_t stack_preview[1];
      42         135 :   if( !_opt_preview ) _opt_preview = stack_preview; /* cmov */
      43             : 
      44             :   /* Read the wksp checkpt header.  165 is large enough to
      45             :      handle decoding an arbitrarily corrupted V1 header (14 worst case
      46             :      SVW encoded ulongs at 9 bytes each followed by a worst case
      47             :      non-'\0' bytes of name at 39==FD_SHMEM_NAME_MAX-1 bytes) and an
      48             :      arbitrarily corrupted V2 header (a 80 byte struct stored
      49             :      uncompressed). */
      50             : 
      51         135 :   uchar buf[ 165 ];
      52         135 :   ulong buf_sz;
      53         135 :   int   err = fd_wksp_private_checkpt_read( path, buf, 165UL, &buf_sz );
      54         135 :   if( FD_UNLIKELY( err ) ) return FD_WKSP_ERR_FAIL;
      55             : 
      56             :   /* If we read a supported valid V2 header, return the requested
      57             :      preview info */
      58             : 
      59         135 :   fd_wksp_checkpt_v2_hdr_t * v2 = (fd_wksp_checkpt_v2_hdr_t *)buf;
      60             : 
      61         135 :   ulong name_len = fd_shmem_name_len( v2->name ); /* tail reading safe */
      62             : 
      63         135 :   if( FD_LIKELY( (sizeof(fd_wksp_checkpt_v2_hdr_t)<=buf_sz                         ) &     /* header not truncated */
      64         135 :                  (v2->magic==FD_WKSP_MAGIC                                         ) &     /* with valid magic */
      65         135 :                  (v2->style==FD_WKSP_CHECKPT_STYLE_V2                              ) &     /* with valid style */
      66         135 :                  (fd_checkpt_frame_style_is_supported( v2->frame_style_compressed )) &     /* with supported compression */
      67         135 :                  (v2->reserved==0U                                                 ) &     /* with expected reserved */
      68         135 :                  (name_len>0UL                                                     ) &     /* with valid name */
      69             :                  /* ignore seed (arbitrary) */
      70         135 :                  (fd_wksp_footprint( v2->part_max, v2->data_max )>0UL              ) ) ) { /* with valid part_max / data_max */
      71          90 :     _opt_preview->style    = v2->style;
      72          90 :     _opt_preview->seed     = v2->seed;
      73          90 :     _opt_preview->part_max = v2->part_max;
      74          90 :     _opt_preview->data_max = v2->data_max;
      75          90 :     memcpy( _opt_preview->name, v2->name, name_len+1UL );
      76          90 :     return FD_WKSP_SUCCESS;
      77          90 :   }
      78             : 
      79             :   /* Otherwise, if we read a supported valid V1 header, return the
      80             :      requested preview info */
      81             : 
      82          45 :   uchar const * cur = buf;
      83             : 
      84          45 :   ulong magic;     cur = fd_ulong_svw_dec( cur, &magic     ); /* safe to tail read */
      85          45 :   ulong style_ul;  cur = fd_ulong_svw_dec( cur, &style_ul  ); /* " */
      86          45 :   ulong seed_ul;   cur = fd_ulong_svw_dec( cur, &seed_ul   ); /* " */
      87          45 :   ulong part_max;  cur = fd_ulong_svw_dec( cur, &part_max  ); /* " */
      88          45 :   ulong data_max;  cur = fd_ulong_svw_dec( cur, &data_max  ); /* " */
      89          45 :   ulong ts_ul;     cur = fd_ulong_svw_dec( cur, &ts_ul     ); /* " */
      90          45 :   ulong app_id;    cur = fd_ulong_svw_dec( cur, &app_id    ); /* " */
      91          45 :   ulong thread_id; cur = fd_ulong_svw_dec( cur, &thread_id ); /* " */
      92          45 :   ulong host_id;   cur = fd_ulong_svw_dec( cur, &host_id   ); /* " */
      93          45 :   ulong cpu_id;    cur = fd_ulong_svw_dec( cur, &cpu_id    ); /* " */
      94          45 :   ulong group_id;  cur = fd_ulong_svw_dec( cur, &group_id  ); /* " */
      95          45 :   ulong tid;       cur = fd_ulong_svw_dec( cur, &tid       ); /* " */
      96          45 :   ulong user_id;   cur = fd_ulong_svw_dec( cur, &user_id   ); /* " */
      97          45 :   /* name_len */   cur = fd_ulong_svw_dec( cur, &name_len  ); /* " */
      98             : 
      99          45 :   char  name[ FD_SHMEM_NAME_MAX ];
     100          45 :   ulong name_len_safe = fd_ulong_min( name_len, FD_SHMEM_NAME_MAX-1UL );
     101          45 :   memcpy( name, cur, name_len_safe );
     102          45 :   name[ name_len_safe ] = '\0';
     103             : 
     104          45 :   if( FD_LIKELY( (((ulong)(cur-buf))<=buf_sz                            ) &     /* header not truncated */
     105          45 :                  (magic   ==FD_WKSP_MAGIC                               ) &     /* with valid magic */
     106          45 :                  (style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1             ) &     /* with valid style */
     107          45 :                  (seed_ul ==(ulong)(uint)seed_ul                        ) &     /* with valid seed */
     108          45 :                  (fd_wksp_footprint( part_max, data_max )>0UL           ) &     /* with valid part_max / data_max */
     109             :                  /* ignore ts_ul     (metadata) */
     110             :                  /* ignore app_id    (metadata) */
     111             :                  /* ignore thread_id (metadata) */
     112             :                  /* ignore host_id   (metadata) */
     113             :                  /* ignore cpu_id    (metadata) */
     114             :                  /* ignore group_id  (metadata) */
     115             :                  /* ignore tid_id    (metadata) */
     116             :                  /* ignore user_id   (metadata) */
     117          45 :                  ((name_len>0UL) & (fd_shmem_name_len( name )==name_len)) ) ) { /* with valid name */
     118          45 :     _opt_preview->style    = (int)style_ul;
     119          45 :     _opt_preview->seed     = (uint)seed_ul;
     120          45 :     _opt_preview->part_max = part_max;
     121          45 :     _opt_preview->data_max = data_max;
     122          45 :     memcpy( _opt_preview->name, name, name_len+1UL );
     123          45 :     return FD_WKSP_SUCCESS;
     124          45 :   }
     125             : 
     126             :   /* Otherwise, this is not a supported valid wksp checkpt header */
     127             : 
     128           0 :   return FD_WKSP_ERR_CORRUPT;
     129          45 : }
     130             : 
     131             : int
     132             : fd_wksp_checkpt_tpool( fd_tpool_t * tpool,
     133             :                        ulong        t0,
     134             :                        ulong        t1,
     135             :                        fd_wksp_t *  wksp,
     136             :                        char const * path,
     137             :                        ulong        mode,
     138             :                        int          style,
     139          54 :                        char const * uinfo ) { /* TODO: CONSIDER ALLOWING SUBSET OF TAGS */
     140             : 
     141             :   /* Check input args */
     142             : 
     143          54 :   if( FD_UNLIKELY( !wksp ) ) {
     144           0 :     FD_LOG_WARNING(( "NULL wksp" ));
     145           0 :     return FD_WKSP_ERR_INVAL;
     146           0 :   }
     147             : 
     148          54 :   if( FD_UNLIKELY( !path ) ) {
     149           0 :     FD_LOG_WARNING(( "NULL path" ));
     150           0 :     return FD_WKSP_ERR_INVAL;
     151           0 :   }
     152             : 
     153          54 :   if( FD_UNLIKELY( mode!=(ulong)(mode_t)mode ) ) {
     154           9 :     FD_LOG_WARNING(( "bad mode" ));
     155           9 :     return FD_WKSP_ERR_INVAL;
     156           9 :   }
     157             : 
     158          45 :   style = fd_int_if( !!style, style, FD_HAS_LZ4 ? FD_WKSP_CHECKPT_STYLE_V3 : FD_WKSP_CHECKPT_STYLE_V2 );
     159             : 
     160          45 :   if( FD_UNLIKELY( !uinfo ) ) uinfo = "";
     161             : 
     162          45 :   char const * binfo = fd_log_build_info;
     163          45 :   if( FD_UNLIKELY( !binfo ) ) binfo = "";
     164             : 
     165             :   /* Checkpt with the appropriate style */
     166             : 
     167          45 :   switch( style ) {
     168          12 :   case FD_WKSP_CHECKPT_STYLE_V1: return fd_wksp_private_checkpt_v1( tpool, t0, t1, wksp, path, mode, uinfo );
     169          24 :   case FD_WKSP_CHECKPT_STYLE_V2: return fd_wksp_private_checkpt_v2( tpool, t0, t1, wksp, path, mode, uinfo,
     170          24 :                                                                     FD_CHECKPT_FRAME_STYLE_RAW );
     171           0 :   case FD_WKSP_CHECKPT_STYLE_V3: return fd_wksp_private_checkpt_v2( tpool, t0, t1, wksp, path, mode, uinfo,
     172           0 :                                                                     FD_CHECKPT_FRAME_STYLE_LZ4 );
     173           0 :   break;
     174          45 :   }
     175             : 
     176           9 :   FD_LOG_WARNING(( "unsupported style" ));
     177           9 :   return FD_WKSP_ERR_INVAL;
     178          45 : }
     179             : 
     180             : int
     181             : fd_wksp_restore_tpool( fd_tpool_t * tpool,
     182             :                        ulong        t0,
     183             :                        ulong        t1,
     184             :                        fd_wksp_t *  wksp,
     185             :                        char const * path,
     186          63 :                        uint         new_seed ) {
     187             : 
     188             :   /* Check input args */
     189             : 
     190          63 :   if( FD_UNLIKELY( !wksp ) ) {
     191           0 :     FD_LOG_WARNING(( "NULL wksp" ));
     192           0 :     return FD_WKSP_ERR_INVAL;
     193           0 :   }
     194             : 
     195          63 :   if( FD_UNLIKELY( !path ) ) {
     196           0 :     FD_LOG_WARNING(( "NULL path" ));
     197           0 :     return FD_WKSP_ERR_INVAL;
     198           0 :   }
     199             : 
     200             :   /* new_seed arbitrary */
     201             : 
     202             :   /* Determine which version to use */
     203             : 
     204          63 :   fd_wksp_preview_t preview[1];
     205          63 :   int err = fd_wksp_preview( path, preview );
     206          63 :   if( FD_UNLIKELY( err ) ) {
     207           0 :     FD_LOG_WARNING(( "\"%s\" does not appear to be a supported wksp checkpt", path ));
     208           0 :     return err;
     209           0 :   }
     210             : 
     211             :   /* Restore with the appropriate version */
     212             : 
     213          63 :   switch( preview->style ) {
     214          21 :   case FD_WKSP_CHECKPT_STYLE_V1: return fd_wksp_private_restore_v1( tpool, t0, t1, wksp, path, new_seed );
     215          42 :   case FD_WKSP_CHECKPT_STYLE_V2: return fd_wksp_private_restore_v2( tpool, t0, t1, wksp, path, new_seed );
     216             :   /* note: v3 is really v2 with compressed frames */
     217           0 :   default: break; /* never get here (preview already checked) */
     218          63 :   }
     219             : 
     220           0 :   FD_LOG_WARNING(( "unsupported style" ));
     221           0 :   return FD_WKSP_ERR_CORRUPT;
     222          63 : }
     223             : 
     224             : int
     225             : fd_wksp_printf( int          fd,
     226             :                 char const * path,
     227          72 :                 int          verbose ) {
     228             : 
     229          72 :   int ret = 0;
     230         207 : # define TRAP(expr) do { int _err = (expr); if( FD_UNLIKELY( _err<0 ) ) { return _err; } ret += _err; } while(0)
     231             : 
     232          72 :   if( verbose<0 ) return ret;
     233             : 
     234          72 :   TRAP( dprintf( fd, "checkpt %s (verbose %i)\n", path, verbose ) );
     235             : 
     236          72 :   fd_wksp_preview_t preview[1];
     237          72 :   int err = fd_wksp_preview( path, preview );
     238          72 :   if( FD_UNLIKELY( err ) )
     239           0 :     TRAP( dprintf( fd, "\tinvalid or unsupported (%i-%s)\n", err, fd_wksp_strerror( err ) ) );
     240          72 :   else
     241          72 :     TRAP( dprintf( fd, "\tstyle                  %-20i\n"
     242          72 :                        "\tname                   %s\n"
     243          72 :                        "\tseed                   %-20u\n"
     244          72 :                        "\tpart_max               %-20lu\n"
     245          72 :                        "\tdata_max               %-20lu\n",
     246          72 :                        preview->style, preview->name, preview->seed, preview->part_max, preview->data_max ) );
     247             : 
     248          72 :   if( verbose<1 ) return ret;
     249             : 
     250          63 :   switch( preview->style ) {
     251          21 :   case FD_WKSP_CHECKPT_STYLE_V1: TRAP( fd_wksp_private_printf_v1( fd, path, verbose ) ); break;
     252          42 :   case FD_WKSP_CHECKPT_STYLE_V2: TRAP( fd_wksp_private_printf_v2( fd, path, verbose ) ); break;
     253             :   /* note: v3 is really v2 with compressed frames */
     254          42 :   default: /* never get here (preview already checked) */
     255           0 :     TRAP( dprintf( fd, "unsupported style" ) );
     256           0 :     break;
     257          63 :   }
     258             : 
     259          63 : # undef TRAP
     260             : 
     261          63 :   return ret;
     262          63 : }

Generated by: LCOV version 1.14