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