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