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 : #include <sys/stat.h>
8 :
9 : /* fd_wksp_private_restore_ulong restores a ulong from the stream in.
10 : Returns 0 on success and, on return, *_val will contain the restored
11 : val. Returns non-zero on failure (will be an errno compat error
12 : code) and, on failure, *_val will be zero. This will implicitly read
13 : ahead for future restores. */
14 :
15 : static int
16 : fd_wksp_private_restore_v1_ulong( fd_io_buffered_istream_t * in,
17 981 : ulong * _val ) {
18 981 : ulong csz;
19 981 : uchar const * buf;
20 981 : uchar _buf[9UL];
21 :
22 : /* Read the encoded val */
23 :
24 981 : ulong peek_sz = fd_io_buffered_istream_peek_sz( in );
25 :
26 981 : if( FD_LIKELY( peek_sz>=9UL ) ) { /* encoded val already prefetched */
27 906 : buf = fd_io_buffered_istream_peek( in );
28 906 : csz = fd_ulong_svw_dec_sz( buf );
29 906 : fd_io_buffered_istream_seek( in, csz );
30 906 : } else { /* encoded val not guaranteed prefetched (this will also implicitly prefetch for future restores) */
31 75 : int err;
32 75 : err = fd_io_buffered_istream_read( in, _buf, 1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
33 75 : csz = fd_ulong_svw_dec_sz( _buf );
34 75 : err = fd_io_buffered_istream_read( in, _buf+1UL, csz-1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
35 75 : buf = _buf;
36 75 : }
37 :
38 : /* Decode encoded val */
39 :
40 981 : *_val = fd_ulong_svw_dec_fixed( buf, csz );
41 981 : return 0;
42 981 : }
43 :
44 : /* fd_wksp_private_restore_buf restores a variable length buffer buf of
45 : maximum size buf_max from the stream in. Returns 0 on success and,
46 : on success, buf will contain the buffer and *_buf_sz will contain the
47 : buffer's size (will be in [0,buf_max]). Returns non-zero on failure
48 : (will be an errno compat error code) and, on failure, buf will be
49 : clobbered and *_buf_sz will be zero. This will implicitly read ahead
50 : for future restores. Zero buf_max is fine (and NULL buf is fine if
51 : buf_max is zero). */
52 :
53 : static int
54 : fd_wksp_private_restore_v1_buf( fd_io_buffered_istream_t * in,
55 : void * buf,
56 : ulong buf_max,
57 378 : ulong * _buf_sz ) {
58 :
59 : /* Restore buf_sz */
60 :
61 378 : ulong buf_sz;
62 378 : int err = fd_wksp_private_restore_v1_ulong( in, &buf_sz );
63 378 : if( FD_UNLIKELY( (!!err) | (buf_sz>buf_max) ) ) { /* I/O error, unexpected EOF, or buf_max too small */
64 0 : if( !!err ) err = EPROTO; /* cmov */
65 0 : *_buf_sz = 0UL;
66 0 : return err;
67 0 : }
68 :
69 : /* Restore buf */
70 :
71 378 : err = fd_io_buffered_istream_read( in, buf, buf_sz );
72 378 : *_buf_sz = fd_ulong_if( !err, buf_sz, 0UL );
73 378 : return err;
74 378 : }
75 :
76 603 : #define RESTORE_ULONG(v) do { \
77 603 : err = fd_wksp_private_restore_v1_ulong( restore, &v ); \
78 603 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
79 603 : } while(0)
80 :
81 : /* Note: on success, v_len==strlen( v ) and will be in [0,max). Assumes
82 : max is positive. */
83 :
84 378 : #define RESTORE_CSTR(v,max) do { \
85 378 : err = fd_wksp_private_restore_v1_buf( restore, v, (max)-1UL, &v##_len ); \
86 378 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
87 378 : v[v##_len] = '\0'; /* v##_len in [0,max) at this point */ \
88 378 : if( FD_UNLIKELY( strlen( v )!=v##_len ) ) { err_info = #v; goto io_err; } \
89 378 : } while(0)
90 :
91 : #define RBUF_ALIGN (4096UL)
92 42 : #define RBUF_FOOTPRINT (65536UL)
93 :
94 : int
95 : fd_wksp_private_restore_v1( fd_tpool_t * tpool,
96 : ulong t0,
97 : ulong t1,
98 : fd_wksp_t * wksp,
99 : char const * path,
100 21 : uint new_seed ) {
101 21 : (void)tpool; (void)t0; (void)t1; /* Note: Thread parallel v1 checkpoint not supported */
102 :
103 21 : FD_LOG_INFO(( "Restore checkpt \"%s\" into wksp \"%s\" (seed %u)", path, wksp->name, new_seed ));
104 :
105 21 : int fd = open( path, O_RDONLY, (mode_t)0 );
106 21 : if( FD_UNLIKELY( fd==-1 ) ) {
107 0 : FD_LOG_WARNING(( "open(\"%s\",O_RDONLY,0) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
108 0 : return FD_WKSP_ERR_FAIL;
109 0 : }
110 :
111 21 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
112 21 : fd_io_buffered_istream_t restore[1];
113 21 : fd_io_buffered_istream_init( restore, fd, rbuf, RBUF_FOOTPRINT );
114 :
115 21 : int err;
116 :
117 21 : err = fd_wksp_private_lock( wksp ); if( FD_UNLIKELY( err ) ) goto fini; /* logs details */
118 :
119 21 : ulong wksp_part_max = wksp->part_max;
120 21 : ulong wksp_data_max = wksp->data_max;
121 21 : ulong wksp_data_lo = wksp->gaddr_lo;
122 21 : ulong wksp_data_hi = wksp->gaddr_hi;
123 21 : fd_wksp_private_pinfo_t * wksp_pinfo = fd_wksp_private_pinfo( wksp );
124 21 : int wksp_dirty = 0;
125 :
126 21 : char const * err_info;
127 :
128 114 : # define RESTORE_TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { err_info = #c; goto stream_err; } } while(0)
129 :
130 21 : ulong orig_part_max;
131 21 : ulong orig_data_max;
132 :
133 21 : {
134 21 : FD_LOG_INFO(( "Restore header (v1)" ));
135 :
136 21 : ulong magic; RESTORE_ULONG( magic );
137 21 : ulong style_ul; RESTORE_ULONG( style_ul );
138 21 : ulong seed_ul; RESTORE_ULONG( seed_ul );
139 21 : ulong part_max; RESTORE_ULONG( part_max );
140 21 : ulong data_max; RESTORE_ULONG( data_max );
141 21 : ulong ts_ul; RESTORE_ULONG( ts_ul ); /* considered metadata */
142 21 : ulong app_id; RESTORE_ULONG( app_id ); /* " */
143 21 : ulong thread_id; RESTORE_ULONG( thread_id ); /* " */
144 21 : ulong host_id; RESTORE_ULONG( host_id ); /* " */
145 21 : ulong cpu_id; RESTORE_ULONG( cpu_id ); /* " */
146 21 : ulong group_id; RESTORE_ULONG( group_id ); /* " */
147 21 : ulong tid; RESTORE_ULONG( tid ); /* " */
148 21 : ulong user_id; RESTORE_ULONG( user_id ); /* " */
149 :
150 21 : char name[ FD_SHMEM_NAME_MAX ]; ulong name_len; RESTORE_CSTR( name, FD_SHMEM_NAME_MAX );
151 :
152 21 : RESTORE_TEST( magic==FD_WKSP_MAGIC );
153 21 : RESTORE_TEST( style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1 );
154 21 : RESTORE_TEST( seed_ul==(ulong)(uint)seed_ul );
155 21 : RESTORE_TEST( fd_wksp_footprint( part_max, data_max )>0UL );
156 21 : RESTORE_TEST( (name_len>0UL) & (fd_shmem_name_len( name )==name_len) );
157 :
158 21 : FD_LOG_INFO(( "Restore metadata (v1)" ));
159 :
160 21 : char ts_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
161 21 : fd_log_wallclock_cstr( (long)ts_ul, ts_cstr );
162 :
163 21 : char app [ FD_LOG_NAME_MAX ]; ulong app_len; RESTORE_CSTR( app, FD_LOG_NAME_MAX );
164 21 : char thread[ FD_LOG_NAME_MAX ]; ulong thread_len; RESTORE_CSTR( thread, FD_LOG_NAME_MAX );
165 21 : char host [ FD_LOG_NAME_MAX ]; ulong host_len; RESTORE_CSTR( host, FD_LOG_NAME_MAX );
166 21 : char cpu [ FD_LOG_NAME_MAX ]; ulong cpu_len; RESTORE_CSTR( cpu, FD_LOG_NAME_MAX );
167 21 : char group [ FD_LOG_NAME_MAX ]; ulong group_len; RESTORE_CSTR( group, FD_LOG_NAME_MAX );
168 21 : char user [ FD_LOG_NAME_MAX ]; ulong user_len; RESTORE_CSTR( user, FD_LOG_NAME_MAX );
169 21 : char binfo [ FD_WKSP_CHECKPT_V1_BINFO_MAX ]; ulong binfo_len; RESTORE_CSTR( binfo, FD_WKSP_CHECKPT_V1_BINFO_MAX );
170 21 : char uinfo [ FD_WKSP_CHECKPT_V1_UINFO_MAX ]; ulong uinfo_len; RESTORE_CSTR( uinfo, FD_WKSP_CHECKPT_V1_UINFO_MAX );
171 :
172 : /* Note: this mirrors v2 */
173 :
174 21 : FD_LOG_INFO(( "\n"
175 21 : "\tstyle %-20i\n" /* verbose 0 info */
176 21 : "\tname %s\n"
177 21 : "\tseed %-20u\n"
178 21 : "\tpart_max %-20lu\n"
179 21 : "\tdata_max %-20lu\n"
180 21 : "\tmagic %016lx\n" /* verbose 1 info */
181 21 : "\twallclock %-20li (%s)\n"
182 21 : "\tapp %-20lu (%s)\n"
183 21 : "\tthread %-20lu (%s)\n"
184 21 : "\thost %-20lu (%s)\n"
185 21 : "\tcpu %-20lu (%s)\n"
186 21 : "\tgroup %-20lu (%s)\n"
187 21 : "\ttid %-20lu\n"
188 21 : "\tuser %-20lu (%s)\n"
189 21 : "\tbinfo\n\t\t%s\n" /* verbose 2 info */
190 21 : "\tuinfo\n\t\t%s",
191 21 : (int)style_ul, name, (uint)seed_ul, part_max, data_max,
192 21 : magic, (long)ts_ul, ts_cstr,
193 21 : app_id, app,
194 21 : thread_id, thread,
195 21 : host_id, host,
196 21 : cpu_id, cpu,
197 21 : group_id, group,
198 21 : tid,
199 21 : user_id, user,
200 21 : binfo,
201 21 : uinfo ));
202 :
203 21 : orig_part_max = part_max;
204 21 : orig_data_max = data_max;
205 21 : }
206 :
207 21 : FD_LOG_INFO(( "Restore allocations" ));
208 :
209 21 : ulong orig_data_lo = fd_wksp_private_data_off( orig_part_max );
210 21 : ulong orig_data_hi = orig_data_lo + orig_data_max;
211 21 : ulong wksp_part_cnt = 0UL;
212 :
213 30 : for(;;) {
214 :
215 : /* Restore the allocation header */
216 :
217 30 : ulong tag; RESTORE_ULONG( tag ); if( FD_UNLIKELY( !tag ) ) break; /* Optimize for lots of partitions */
218 9 : ulong gaddr_lo; RESTORE_ULONG( gaddr_lo );
219 9 : ulong sz; RESTORE_ULONG( sz );
220 :
221 9 : ulong gaddr_hi = gaddr_lo + sz;
222 :
223 9 : RESTORE_TEST( (orig_data_lo<=gaddr_lo) & (gaddr_lo<gaddr_hi) & (gaddr_hi<=orig_data_hi) );
224 :
225 9 : if( FD_UNLIKELY( wksp_part_cnt>=wksp_part_max ) ) {
226 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because too few wksp partitions (part_max checkpt %lu, wksp %lu)",
227 0 : path, wksp->name, orig_part_max, wksp_part_max ));
228 0 : goto unlock;
229 0 : }
230 :
231 9 : if( FD_UNLIKELY( !((wksp_data_lo<=gaddr_lo) & (gaddr_hi<=wksp_data_hi)) ) ) {
232 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because checkpt partition [0x%016lx,0x%016lx) tag %lu "
233 0 : "does not fit into wksp data region [0x%016lx,0x%016lx) (data_max checkpt %lu, wksp %lu)",
234 0 : path, wksp->name, gaddr_lo, gaddr_hi, tag, wksp_data_lo, wksp_data_hi, orig_data_max, wksp_data_max ));
235 0 : goto unlock;
236 0 : }
237 :
238 : /* Restore the allocation payload into the wksp and record this
239 : allocation in the wksp */
240 :
241 9 : wksp_dirty = 1;
242 :
243 : #if FD_HAS_DEEPASAN
244 : /* Poison the restored allocations. Potentially under poison to respect
245 : manual poisoning alignment requirements. Don't poison if the allocation
246 : is smaller than FD_ASAN_ALIGN. */
247 : ulong laddr_lo = (ulong)fd_wksp_laddr_fast( wksp, gaddr_lo );
248 : ulong laddr_hi = laddr_lo + sz;
249 : ulong aligned_laddr_lo = fd_ulong_align_up( laddr_lo, FD_ASAN_ALIGN );
250 : ulong aligned_laddr_hi = fd_ulong_align_dn( laddr_hi, FD_ASAN_ALIGN );
251 : if( aligned_laddr_lo < aligned_laddr_hi ) {
252 : fd_asan_poison( (void*)aligned_laddr_lo, aligned_laddr_hi - aligned_laddr_lo );
253 : }
254 : #endif
255 :
256 9 : err = fd_io_buffered_istream_read( restore, fd_wksp_laddr_fast( wksp, gaddr_lo ), sz );
257 9 : if( FD_UNLIKELY( err ) ) {
258 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because of I/O error (%i-%s)",
259 0 : path, wksp->name, err, fd_io_strerror( err ) ));
260 0 : goto unlock;
261 0 : }
262 :
263 9 : wksp_pinfo[ wksp_part_cnt ].gaddr_lo = gaddr_lo;
264 9 : wksp_pinfo[ wksp_part_cnt ].gaddr_hi = gaddr_hi;
265 9 : wksp_pinfo[ wksp_part_cnt ].tag = tag;
266 9 : wksp_part_cnt++;
267 9 : }
268 :
269 21 : FD_LOG_INFO(( "Rebuilding wksp with restored allocations" ));
270 :
271 21 : wksp_dirty = 1;
272 :
273 343740 : for( ulong i=wksp_part_cnt; i<wksp_part_max; i++ ) wksp_pinfo[ i ].tag = 0UL; /* Remove all remaining old allocations */
274 21 : err = fd_wksp_rebuild( wksp, new_seed ); /* logs details */
275 21 : if( FD_UNLIKELY( err ) ) { /* wksp dirty */
276 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because of rebuild error", path, wksp->name ));
277 0 : goto unlock;
278 0 : }
279 :
280 21 : wksp_dirty = 0;
281 :
282 21 : FD_LOG_INFO(( "Restore successful" ));
283 :
284 : /* err = 0 at this point */
285 :
286 21 : unlock: /* note: wksp locked at this point */
287 :
288 : /* If wksp is not clean, reset it to get it back to a clean state */
289 :
290 21 : if( wksp_dirty ) {
291 0 : FD_LOG_WARNING(( "wksp \"%s\" dirty; attempting to reset it and continue", wksp->name ));
292 0 : for( ulong i=0UL; i<wksp_part_max; i++ ) wksp_pinfo[ i ].tag = 0UL;
293 0 : fd_wksp_rebuild( wksp, new_seed ); /* logs details */
294 0 : err = FD_WKSP_ERR_CORRUPT;
295 0 : }
296 :
297 21 : fd_wksp_private_unlock( wksp );
298 :
299 21 : fini: /* Note: wksp unlocked at this point */
300 :
301 21 : fd_io_buffered_istream_fini( restore );
302 :
303 21 : if( FD_UNLIKELY( close( fd ) ) )
304 0 : FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
305 :
306 21 : return err;
307 :
308 0 : io_err: /* Note: wksp locked at this point */
309 :
310 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed (%s) due to I/O error (%i-%s)",
311 0 : path, wksp->name, err_info, err, fd_io_strerror( err ) ));
312 0 : err = FD_WKSP_ERR_FAIL;
313 :
314 0 : goto unlock;
315 :
316 0 : stream_err: /* Note: wksp locked at this point */
317 :
318 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed due to checkpt format error (%s)", path, wksp->name, err_info ));
319 0 : err = FD_WKSP_ERR_FAIL;
320 :
321 0 : goto unlock;
322 :
323 21 : # undef RESTORE_TEST
324 21 : }
325 :
326 : int
327 : fd_wksp_private_printf_v1( int out,
328 : char const * path,
329 21 : int verbose ) {
330 :
331 54 : # define TRAP(x) do { err = (x); if( FD_UNLIKELY( err<0 ) ) { ret = err; goto done; } ret += err; } while(0)
332 105 : # define RESTORE_TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { err_info = #c; goto stream_err; } } while(0)
333 :
334 21 : int fd = -1;
335 21 : fd_io_buffered_istream_t * restore = NULL;
336 21 : int ret = 0;
337 21 : int err;
338 21 : char const * err_info;
339 21 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
340 21 : fd_io_buffered_istream_t _restore[1];
341 :
342 21 : fd = open( path, O_RDONLY, (mode_t)0 );
343 21 : if( FD_UNLIKELY( fd==-1 ) ) TRAP( dprintf( out, "\topen(O_RDONLY) failed (%i-%s)\n", errno, fd_io_strerror( errno ) ) );
344 :
345 21 : restore = fd_io_buffered_istream_init( _restore, fd, rbuf, RBUF_FOOTPRINT );
346 :
347 : /* Print the header and metadata (note: fd_wksp_private_printf
348 : already printed the preview info and verbose is at least 1) */
349 :
350 21 : ulong orig_part_max;
351 21 : ulong orig_data_max;
352 :
353 21 : {
354 21 : ulong magic; RESTORE_ULONG( magic );
355 21 : ulong style_ul; RESTORE_ULONG( style_ul );
356 21 : ulong seed_ul; RESTORE_ULONG( seed_ul );
357 21 : ulong part_max; RESTORE_ULONG( part_max );
358 21 : ulong data_max; RESTORE_ULONG( data_max );
359 21 : ulong ts_ul; RESTORE_ULONG( ts_ul ); /* considered metadata */
360 21 : ulong app_id; RESTORE_ULONG( app_id ); /* " */
361 21 : ulong thread_id; RESTORE_ULONG( thread_id ); /* " */
362 21 : ulong host_id; RESTORE_ULONG( host_id ); /* " */
363 21 : ulong cpu_id; RESTORE_ULONG( cpu_id ); /* " */
364 21 : ulong group_id; RESTORE_ULONG( group_id ); /* " */
365 21 : ulong tid; RESTORE_ULONG( tid ); /* " */
366 21 : ulong user_id; RESTORE_ULONG( user_id ); /* " */
367 :
368 21 : char name[ FD_SHMEM_NAME_MAX ]; ulong name_len; RESTORE_CSTR( name, FD_SHMEM_NAME_MAX );
369 :
370 21 : RESTORE_TEST( magic==FD_WKSP_MAGIC );
371 21 : RESTORE_TEST( style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1 );
372 21 : RESTORE_TEST( seed_ul==(ulong)(uint)seed_ul );
373 21 : RESTORE_TEST( fd_wksp_footprint( part_max, data_max )>0UL );
374 21 : RESTORE_TEST( (name_len>0UL) & (fd_shmem_name_len( name )==name_len) );
375 :
376 21 : char app [ FD_LOG_NAME_MAX ]; ulong app_len; RESTORE_CSTR( app, FD_LOG_NAME_MAX );
377 21 : char thread[ FD_LOG_NAME_MAX ]; ulong thread_len; RESTORE_CSTR( thread, FD_LOG_NAME_MAX );
378 21 : char host [ FD_LOG_NAME_MAX ]; ulong host_len; RESTORE_CSTR( host, FD_LOG_NAME_MAX );
379 21 : char cpu [ FD_LOG_NAME_MAX ]; ulong cpu_len; RESTORE_CSTR( cpu, FD_LOG_NAME_MAX );
380 21 : char group [ FD_LOG_NAME_MAX ]; ulong group_len; RESTORE_CSTR( group, FD_LOG_NAME_MAX );
381 21 : char user [ FD_LOG_NAME_MAX ]; ulong user_len; RESTORE_CSTR( user, FD_LOG_NAME_MAX );
382 21 : char binfo [ FD_WKSP_CHECKPT_V1_BINFO_MAX ]; ulong binfo_len; RESTORE_CSTR( binfo, FD_WKSP_CHECKPT_V1_BINFO_MAX );
383 21 : char uinfo [ FD_WKSP_CHECKPT_V1_UINFO_MAX ]; ulong uinfo_len; RESTORE_CSTR( uinfo, FD_WKSP_CHECKPT_V1_UINFO_MAX );
384 :
385 21 : char ts_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
386 21 : fd_log_wallclock_cstr( (long)ts_ul, ts_cstr );
387 :
388 : /* Note: this mirrors v2 printf */
389 :
390 21 : if( verbose>=1 )
391 21 : TRAP( dprintf( out,
392 : //"\tstyle %-20i\n" /* verbose 0 info (already printed) */
393 : //"\tname %s\n"
394 : //"\tseed %-20u\n"
395 : //"\tpart_max %-20lu\n"
396 : //"\tdata_max %-20lu\n"
397 21 : "\tmagic %016lx\n" /* verbose 1 info */
398 21 : "\twallclock %-20li (%s)\n"
399 21 : "\tapp %-20lu (%s)\n"
400 21 : "\tthread %-20lu (%s)\n"
401 21 : "\thost %-20lu (%s)\n"
402 21 : "\tcpu %-20lu (%s)\n"
403 21 : "\tgroup %-20lu (%s)\n"
404 21 : "\ttid %-20lu\n"
405 21 : "\tuser %-20lu (%s)\n",
406 21 : magic,
407 21 : (long)ts_ul, ts_cstr,
408 21 : app_id, app,
409 21 : thread_id, thread,
410 21 : host_id, host,
411 21 : cpu_id, cpu,
412 21 : group_id, group,
413 21 : tid,
414 21 : user_id, user ) );
415 21 : if( verbose>=2 )
416 18 : TRAP( dprintf( out, "\tbinfo\n\t\t%s\n"
417 21 : "\tuinfo\n\t\t%s\n", binfo, uinfo ) ); /* verbose 2 info */
418 :
419 21 : orig_part_max = part_max;
420 21 : orig_data_max = data_max;
421 21 : }
422 :
423 21 : if( verbose>=3 ) {
424 :
425 9 : ulong orig_data_lo = fd_wksp_private_data_off( orig_part_max );
426 9 : ulong orig_data_hi = orig_data_lo + orig_data_max;
427 :
428 9 : ulong alloc_tot = 0UL;
429 9 : ulong alloc_cnt = 0UL;
430 9 : ulong alloc_big = 0UL;
431 :
432 9 : if( verbose>=4 ) TRAP( dprintf( out, "\tgaddr [0x%016lx,0x%016lx)\n", orig_data_lo, orig_data_hi ) );
433 :
434 9 : for(;;) {
435 :
436 : /* Print partition metadata */
437 :
438 9 : ulong tag; RESTORE_ULONG( tag ); if( !tag ) break; /* no more partitions */
439 0 : ulong gaddr_lo; RESTORE_ULONG( gaddr_lo );
440 0 : ulong sz; RESTORE_ULONG( sz );
441 :
442 0 : ulong gaddr_hi = gaddr_lo + sz;
443 :
444 0 : RESTORE_TEST( (orig_data_lo<=gaddr_lo) & (gaddr_lo<gaddr_hi) & (gaddr_hi<=orig_data_hi) );
445 :
446 0 : if( verbose>=4 ) TRAP( dprintf( out, "\tpartition [0x%016lx,0x%016lx) sz %20lu tag %20lu\n", gaddr_lo, gaddr_hi, sz, tag ) );
447 :
448 0 : alloc_cnt += 1UL;
449 0 : alloc_tot += sz;
450 0 : alloc_big = fd_ulong_max( alloc_big, sz );
451 :
452 : /* Skip partition data (TODO: add verbose 5 for pretty printing
453 : the raw partition data too). */
454 :
455 0 : int err = fd_io_buffered_istream_skip( restore, sz );
456 0 : if( FD_UNLIKELY( err ) ) { err_info = "partition data"; goto io_err; }
457 0 : }
458 :
459 9 : TRAP( dprintf( out, "\t%20lu bytes used (%20lu blocks, largest %20lu bytes)\n"
460 9 : "\t%20lu bytes free (%20s blocks, largest %20s bytes)\n"
461 9 : "\t%20lu errors detected\n"
462 9 : , alloc_tot, alloc_cnt, alloc_big, orig_data_max-alloc_tot, "-", "-", 0UL /* no err if we got here */ ) );
463 :
464 9 : }
465 :
466 21 : done:
467 21 : if( FD_LIKELY( restore ) ) fd_io_buffered_istream_fini( restore );
468 21 : if( FD_LIKELY( fd!=-1 ) ) close( fd ); /* TODO: Consider trapping (but we might be in a dprintf err) */
469 21 : return ret;
470 :
471 0 : io_err:
472 0 : if( err<0 ) TRAP( dprintf( out, "\tFAIL: io: %s (unexpected end of file)\n", err_info ) );
473 0 : else TRAP( dprintf( out, "\tFAIL: io: %s (%i-%s)\n", err_info, err, fd_io_strerror( err ) ) );
474 0 : goto done;
475 :
476 0 : stream_err:
477 0 : TRAP( dprintf( fd, "\tFAIL: stream: %s\n", err_info ) );
478 0 : goto done;
479 :
480 0 : # undef RESTORE_TEST
481 0 : # undef TRAP
482 0 : }
483 :
484 : #undef RBUF_FOOTPRINT
485 : #undef RBUF_ALIGN
486 :
487 : #undef RESTORE_CSTR
488 : #undef RESTORE_ULONG
|