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 0 : ulong * _buf_sz ) { /* Assumes non-NULL */
21 :
22 0 : int fd = open( path, O_RDONLY, (mode_t)0 );
23 0 : if( FD_UNLIKELY( fd==-1 ) ) return errno;
24 :
25 0 : int err = fd_io_read( fd, buf, 12UL, buf_max, _buf_sz );
26 :
27 0 : 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 0 : return err;
31 0 : }
32 :
33 : int
34 : fd_wksp_preview( char const * path,
35 0 : fd_wksp_preview_t * _opt_preview ) {
36 :
37 : /* Check input args */
38 :
39 0 : if( FD_UNLIKELY( !path ) ) return FD_WKSP_ERR_INVAL;
40 :
41 0 : fd_wksp_preview_t stack_preview[1];
42 0 : 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 0 : uchar buf[ 165 ];
52 0 : ulong buf_sz;
53 0 : int err = fd_wksp_private_checkpt_read( path, buf, 165UL, &buf_sz );
54 0 : 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 0 : fd_wksp_checkpt_v2_hdr_t * v2 = (fd_wksp_checkpt_v2_hdr_t *)buf;
60 :
61 0 : ulong name_len = fd_shmem_name_len( v2->name ); /* tail reading safe */
62 :
63 0 : if( FD_LIKELY( (sizeof(fd_wksp_checkpt_v2_hdr_t)<=buf_sz ) & /* header not truncated */
64 0 : (v2->magic==FD_WKSP_MAGIC ) & /* with valid magic */
65 0 : (v2->style==FD_WKSP_CHECKPT_STYLE_V2 ) & /* with valid style */
66 0 : (fd_checkpt_frame_style_is_supported( v2->frame_style_compressed )) & /* with supported compression */
67 0 : (v2->reserved==0U ) & /* with expected reserved */
68 0 : (name_len>0UL ) & /* with valid name */
69 : /* ignore seed (arbitrary) */
70 0 : (fd_wksp_footprint( v2->part_max, v2->data_max )>0UL ) ) ) { /* with valid part_max / data_max */
71 0 : _opt_preview->style = v2->style;
72 0 : _opt_preview->seed = v2->seed;
73 0 : _opt_preview->part_max = v2->part_max;
74 0 : _opt_preview->data_max = v2->data_max;
75 0 : memcpy( _opt_preview->name, v2->name, name_len+1UL );
76 0 : return FD_WKSP_SUCCESS;
77 0 : }
78 :
79 : /* Otherwise, if we read a supported valid V1 header, return the
80 : requested preview info */
81 :
82 0 : uchar const * cur = buf;
83 :
84 0 : ulong magic; cur = fd_ulong_svw_dec( cur, &magic ); /* safe to tail read */
85 0 : ulong style_ul; cur = fd_ulong_svw_dec( cur, &style_ul ); /* " */
86 0 : ulong seed_ul; cur = fd_ulong_svw_dec( cur, &seed_ul ); /* " */
87 0 : ulong part_max; cur = fd_ulong_svw_dec( cur, &part_max ); /* " */
88 0 : ulong data_max; cur = fd_ulong_svw_dec( cur, &data_max ); /* " */
89 0 : ulong ts_ul; cur = fd_ulong_svw_dec( cur, &ts_ul ); /* " */
90 0 : ulong app_id; cur = fd_ulong_svw_dec( cur, &app_id ); /* " */
91 0 : ulong thread_id; cur = fd_ulong_svw_dec( cur, &thread_id ); /* " */
92 0 : ulong host_id; cur = fd_ulong_svw_dec( cur, &host_id ); /* " */
93 0 : ulong cpu_id; cur = fd_ulong_svw_dec( cur, &cpu_id ); /* " */
94 0 : ulong group_id; cur = fd_ulong_svw_dec( cur, &group_id ); /* " */
95 0 : ulong tid; cur = fd_ulong_svw_dec( cur, &tid ); /* " */
96 0 : ulong user_id; cur = fd_ulong_svw_dec( cur, &user_id ); /* " */
97 0 : /* name_len */ cur = fd_ulong_svw_dec( cur, &name_len ); /* " */
98 :
99 0 : char name[ FD_SHMEM_NAME_MAX ];
100 0 : ulong name_len_safe = fd_ulong_min( name_len, FD_SHMEM_NAME_MAX-1UL );
101 0 : memcpy( name, cur, name_len_safe );
102 0 : name[ name_len_safe ] = '\0';
103 :
104 0 : if( FD_LIKELY( (((ulong)(cur-buf))<=buf_sz ) & /* header not truncated */
105 0 : (magic ==FD_WKSP_MAGIC ) & /* with valid magic */
106 0 : (style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1 ) & /* with valid style */
107 0 : (seed_ul ==(ulong)(uint)seed_ul ) & /* with valid seed */
108 0 : (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 0 : ((name_len>0UL) & (fd_shmem_name_len( name )==name_len)) ) ) { /* with valid name */
118 0 : _opt_preview->style = (int)style_ul;
119 0 : _opt_preview->seed = (uint)seed_ul;
120 0 : _opt_preview->part_max = part_max;
121 0 : _opt_preview->data_max = data_max;
122 0 : memcpy( _opt_preview->name, name, name_len+1UL );
123 0 : return FD_WKSP_SUCCESS;
124 0 : }
125 :
126 : /* Otherwise, this is not a supported valid wksp checkpt header */
127 :
128 0 : return FD_WKSP_ERR_CORRUPT;
129 0 : }
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 0 : char const * uinfo ) { /* TODO: CONSIDER ALLOWING SUBSET OF TAGS */
140 :
141 : /* Check input args */
142 :
143 0 : if( FD_UNLIKELY( !wksp ) ) {
144 0 : FD_LOG_WARNING(( "NULL wksp" ));
145 0 : return FD_WKSP_ERR_INVAL;
146 0 : }
147 :
148 0 : if( FD_UNLIKELY( !path ) ) {
149 0 : FD_LOG_WARNING(( "NULL path" ));
150 0 : return FD_WKSP_ERR_INVAL;
151 0 : }
152 :
153 0 : if( FD_UNLIKELY( mode!=(ulong)(mode_t)mode ) ) {
154 0 : FD_LOG_WARNING(( "bad mode" ));
155 0 : return FD_WKSP_ERR_INVAL;
156 0 : }
157 :
158 0 : style = fd_int_if( !!style, style, FD_HAS_LZ4 ? FD_WKSP_CHECKPT_STYLE_V3 : FD_WKSP_CHECKPT_STYLE_V2 );
159 :
160 0 : if( FD_UNLIKELY( !uinfo ) ) uinfo = "";
161 :
162 0 : char const * binfo = fd_log_build_info;
163 0 : if( FD_UNLIKELY( !binfo ) ) binfo = "";
164 :
165 : /* Checkpt with the appropriate style */
166 :
167 0 : switch( style ) {
168 0 : case FD_WKSP_CHECKPT_STYLE_V1: return fd_wksp_private_checkpt_v1( tpool, t0, t1, wksp, path, mode, uinfo );
169 0 : case FD_WKSP_CHECKPT_STYLE_V2: return fd_wksp_private_checkpt_v2( tpool, t0, t1, wksp, path, mode, uinfo,
170 0 : 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 0 : }
175 :
176 0 : FD_LOG_WARNING(( "unsupported style" ));
177 0 : return FD_WKSP_ERR_INVAL;
178 0 : }
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 0 : uint new_seed ) {
187 :
188 : /* Check input args */
189 :
190 0 : if( FD_UNLIKELY( !wksp ) ) {
191 0 : FD_LOG_WARNING(( "NULL wksp" ));
192 0 : return FD_WKSP_ERR_INVAL;
193 0 : }
194 :
195 0 : 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 0 : fd_wksp_preview_t preview[1];
205 0 : int err = fd_wksp_preview( path, preview );
206 0 : 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 0 : switch( preview->style ) {
214 0 : case FD_WKSP_CHECKPT_STYLE_V1: return fd_wksp_private_restore_v1( tpool, t0, t1, wksp, path, new_seed );
215 0 : 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 0 : }
219 :
220 0 : FD_LOG_WARNING(( "unsupported style" ));
221 0 : return FD_WKSP_ERR_CORRUPT;
222 0 : }
223 :
224 : int
225 : fd_wksp_printf( int fd,
226 : char const * path,
227 0 : int verbose ) {
228 :
229 0 : int ret = 0;
230 0 : # define TRAP(expr) do { int _err = (expr); if( FD_UNLIKELY( _err<0 ) ) { return _err; } ret += _err; } while(0)
231 :
232 0 : if( verbose<0 ) return ret;
233 :
234 0 : TRAP( dprintf( fd, "checkpt %s (verbose %i)\n", path, verbose ) );
235 :
236 0 : fd_wksp_preview_t preview[1];
237 0 : int err = fd_wksp_preview( path, preview );
238 0 : if( FD_UNLIKELY( err ) )
239 0 : TRAP( dprintf( fd, "\tinvalid or unsupported (%i-%s)\n", err, fd_wksp_strerror( err ) ) );
240 0 : else
241 0 : TRAP( dprintf( fd, "\tstyle %-20i\n"
242 0 : "\tname %s\n"
243 0 : "\tseed %-20u\n"
244 0 : "\tpart_max %-20lu\n"
245 0 : "\tdata_max %-20lu\n",
246 0 : preview->style, preview->name, preview->seed, preview->part_max, preview->data_max ) );
247 :
248 0 : if( verbose<1 ) return ret;
249 :
250 0 : switch( preview->style ) {
251 0 : case FD_WKSP_CHECKPT_STYLE_V1: TRAP( fd_wksp_private_printf_v1( fd, path, verbose ) ); break;
252 0 : 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 0 : default: /* never get here (preview already checked) */
255 0 : TRAP( dprintf( fd, "unsupported style" ) );
256 0 : break;
257 0 : }
258 :
259 0 : # undef TRAP
260 :
261 0 : return ret;
262 0 : }
|