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 0 : ulong * _val ) {
19 0 : ulong csz;
20 0 : uchar const * buf;
21 0 : uchar _buf[9UL];
22 :
23 : /* Read the encoded val */
24 :
25 0 : ulong peek_sz = fd_io_buffered_istream_peek_sz( in );
26 :
27 0 : if( FD_LIKELY( peek_sz>=9UL ) ) { /* encoded val already prefetched */
28 0 : buf = fd_io_buffered_istream_peek( in );
29 0 : csz = fd_ulong_svw_dec_sz( buf );
30 0 : fd_io_buffered_istream_seek( in, csz );
31 0 : } else { /* encoded val not guaranteed prefetched (this will also implicitly prefetch for future restores) */
32 0 : int err;
33 0 : err = fd_io_buffered_istream_read( in, _buf, 1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
34 0 : csz = fd_ulong_svw_dec_sz( _buf );
35 0 : err = fd_io_buffered_istream_read( in, _buf+1UL, csz-1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
36 0 : buf = _buf;
37 0 : }
38 :
39 : /* Decode encoded val */
40 :
41 0 : *_val = fd_ulong_svw_dec_fixed( buf, csz );
42 0 : return 0;
43 0 : }
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 0 : ulong * _buf_sz ) {
59 :
60 : /* Restore buf_sz */
61 :
62 0 : ulong buf_sz;
63 0 : int err = fd_wksp_private_restore_v1_ulong( in, &buf_sz );
64 0 : 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 0 : err = fd_io_buffered_istream_read( in, buf, buf_sz );
73 0 : *_buf_sz = fd_ulong_if( !err, buf_sz, 0UL );
74 0 : return err;
75 0 : }
76 :
77 0 : #define RESTORE_ULONG(v) do { \
78 0 : err = fd_wksp_private_restore_v1_ulong( restore, &v ); \
79 0 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
80 0 : } while(0)
81 :
82 : /* Note: on success, v_len==strlen( v ) and will be in [0,max). Assumes
83 : max is positive. */
84 :
85 0 : #define RESTORE_CSTR(v,max) do { \
86 0 : err = fd_wksp_private_restore_v1_buf( restore, v, (max)-1UL, &v##_len ); \
87 0 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
88 0 : v[v##_len] = '\0'; /* v##_len in [0,max) at this point */ \
89 0 : if( FD_UNLIKELY( strlen( v )!=v##_len ) ) { err_info = #v; goto io_err; } \
90 0 : } while(0)
91 :
92 : #define RBUF_ALIGN (4096UL)
93 0 : #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 0 : uint new_seed ) {
102 0 : (void)tpool; (void)t0; (void)t1; /* Note: Thread parallel v1 checkpoint not supported */
103 :
104 0 : FD_LOG_INFO(( "Restore checkpt \"%s\" into wksp \"%s\" (seed %u)", path, wksp->name, new_seed ));
105 :
106 0 : int fd = open( path, O_RDONLY, (mode_t)0 );
107 0 : 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 0 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
113 0 : fd_io_buffered_istream_t restore[1];
114 0 : fd_io_buffered_istream_init( restore, fd, rbuf, RBUF_FOOTPRINT );
115 :
116 0 : int err;
117 :
118 0 : err = fd_wksp_private_lock( wksp ); if( FD_UNLIKELY( err ) ) goto fini; /* logs details */
119 :
120 0 : ulong wksp_part_max = wksp->part_max;
121 0 : ulong wksp_data_max = wksp->data_max;
122 0 : ulong wksp_data_lo = wksp->gaddr_lo;
123 0 : ulong wksp_data_hi = wksp->gaddr_hi;
124 0 : fd_wksp_private_pinfo_t * wksp_pinfo = fd_wksp_private_pinfo( wksp );
125 0 : int wksp_dirty = 0;
126 :
127 0 : char const * err_info;
128 :
129 0 : # define RESTORE_TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { err_info = #c; goto stream_err; } } while(0)
130 :
131 0 : ulong orig_part_max;
132 0 : ulong orig_data_max;
133 :
134 0 : {
135 0 : FD_LOG_INFO(( "Restore header (v1)" ));
136 :
137 0 : ulong magic; RESTORE_ULONG( magic );
138 0 : ulong style_ul; RESTORE_ULONG( style_ul );
139 0 : ulong seed_ul; RESTORE_ULONG( seed_ul );
140 0 : ulong part_max; RESTORE_ULONG( part_max );
141 0 : ulong data_max; RESTORE_ULONG( data_max );
142 0 : ulong ts_ul; RESTORE_ULONG( ts_ul ); /* considered metadata */
143 0 : ulong app_id; RESTORE_ULONG( app_id ); /* " */
144 0 : ulong thread_id; RESTORE_ULONG( thread_id ); /* " */
145 0 : ulong host_id; RESTORE_ULONG( host_id ); /* " */
146 0 : ulong cpu_id; RESTORE_ULONG( cpu_id ); /* " */
147 0 : ulong group_id; RESTORE_ULONG( group_id ); /* " */
148 0 : ulong tid; RESTORE_ULONG( tid ); /* " */
149 0 : ulong user_id; RESTORE_ULONG( user_id ); /* " */
150 :
151 0 : char name[ FD_SHMEM_NAME_MAX ]; ulong name_len; RESTORE_CSTR( name, FD_SHMEM_NAME_MAX );
152 :
153 0 : RESTORE_TEST( magic==FD_WKSP_MAGIC );
154 0 : RESTORE_TEST( style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1 );
155 0 : RESTORE_TEST( seed_ul==(ulong)(uint)seed_ul );
156 0 : RESTORE_TEST( fd_wksp_footprint( part_max, data_max )>0UL );
157 0 : RESTORE_TEST( (name_len>0UL) & (fd_shmem_name_len( name )==name_len) );
158 :
159 0 : FD_LOG_INFO(( "Restore metadata (v1)" ));
160 :
161 0 : char ts_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
162 0 : fd_log_wallclock_cstr( (long)ts_ul, ts_cstr );
163 :
164 0 : char app [ FD_LOG_NAME_MAX ]; ulong app_len; RESTORE_CSTR( app, FD_LOG_NAME_MAX );
165 0 : char thread[ FD_LOG_NAME_MAX ]; ulong thread_len; RESTORE_CSTR( thread, FD_LOG_NAME_MAX );
166 0 : char host [ FD_LOG_NAME_MAX ]; ulong host_len; RESTORE_CSTR( host, FD_LOG_NAME_MAX );
167 0 : char cpu [ FD_LOG_NAME_MAX ]; ulong cpu_len; RESTORE_CSTR( cpu, FD_LOG_NAME_MAX );
168 0 : char group [ FD_LOG_NAME_MAX ]; ulong group_len; RESTORE_CSTR( group, FD_LOG_NAME_MAX );
169 0 : char user [ FD_LOG_NAME_MAX ]; ulong user_len; RESTORE_CSTR( user, FD_LOG_NAME_MAX );
170 0 : char binfo [ FD_WKSP_CHECKPT_V1_BINFO_MAX ]; ulong binfo_len; RESTORE_CSTR( binfo, FD_WKSP_CHECKPT_V1_BINFO_MAX );
171 0 : 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 0 : FD_LOG_INFO(( "\n"
176 0 : "\tstyle %-20i\n" /* verbose 0 info */
177 0 : "\tname %s\n"
178 0 : "\tseed %-20u\n"
179 0 : "\tpart_max %-20lu\n"
180 0 : "\tdata_max %-20lu\n"
181 0 : "\tmagic %016lx\n" /* verbose 1 info */
182 0 : "\twallclock %-20li (%s)\n"
183 0 : "\tapp %-20lu (%s)\n"
184 0 : "\tthread %-20lu (%s)\n"
185 0 : "\thost %-20lu (%s)\n"
186 0 : "\tcpu %-20lu (%s)\n"
187 0 : "\tgroup %-20lu (%s)\n"
188 0 : "\ttid %-20lu\n"
189 0 : "\tuser %-20lu (%s)\n"
190 0 : "\tbinfo\n\t\t%s\n" /* verbose 2 info */
191 0 : "\tuinfo\n\t\t%s",
192 0 : (int)style_ul, name, (uint)seed_ul, part_max, data_max,
193 0 : magic, (long)ts_ul, ts_cstr,
194 0 : app_id, app,
195 0 : thread_id, thread,
196 0 : host_id, host,
197 0 : cpu_id, cpu,
198 0 : group_id, group,
199 0 : tid,
200 0 : user_id, user,
201 0 : binfo,
202 0 : uinfo ));
203 :
204 0 : orig_part_max = part_max;
205 0 : orig_data_max = data_max;
206 0 : }
207 :
208 0 : FD_LOG_INFO(( "Restore allocations" ));
209 :
210 0 : ulong orig_data_lo = fd_wksp_private_data_off( orig_part_max );
211 0 : ulong orig_data_hi = orig_data_lo + orig_data_max;
212 0 : ulong wksp_part_cnt = 0UL;
213 :
214 0 : for(;;) {
215 :
216 : /* Restore the allocation header */
217 :
218 0 : ulong tag; RESTORE_ULONG( tag ); if( FD_UNLIKELY( !tag ) ) break; /* Optimize for lots of partitions */
219 0 : ulong gaddr_lo; RESTORE_ULONG( gaddr_lo );
220 0 : ulong sz; RESTORE_ULONG( sz );
221 :
222 0 : ulong gaddr_hi = gaddr_lo + sz;
223 :
224 0 : RESTORE_TEST( (orig_data_lo<=gaddr_lo) & (gaddr_lo<gaddr_hi) & (gaddr_hi<=orig_data_hi) );
225 :
226 0 : 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 0 : 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 0 : 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 0 : err = fd_io_buffered_istream_read( restore, fd_wksp_laddr_fast( wksp, gaddr_lo ), sz );
251 0 : 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 0 : wksp_pinfo[ wksp_part_cnt ].gaddr_lo = gaddr_lo;
258 0 : wksp_pinfo[ wksp_part_cnt ].gaddr_hi = gaddr_hi;
259 0 : wksp_pinfo[ wksp_part_cnt ].tag = tag;
260 0 : wksp_part_cnt++;
261 0 : }
262 :
263 0 : FD_LOG_INFO(( "Rebuilding wksp with restored allocations" ));
264 :
265 0 : wksp_dirty = 1;
266 :
267 0 : for( ulong i=wksp_part_cnt; i<wksp_part_max; i++ ) wksp_pinfo[ i ].tag = 0UL; /* Remove all remaining old allocations */
268 0 : err = fd_wksp_rebuild( wksp, new_seed ); /* logs details */
269 0 : 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 0 : wksp_dirty = 0;
279 :
280 0 : FD_LOG_INFO(( "Restore successful" ));
281 :
282 : /* err = 0 at this point */
283 :
284 0 : 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 0 : 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 0 : fd_wksp_private_unlock( wksp );
299 :
300 0 : fini: /* Note: wksp unlocked at this point */
301 :
302 0 : fd_io_buffered_istream_fini( restore );
303 :
304 0 : 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 0 : 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 0 : # undef RESTORE_TEST
325 0 : }
326 :
327 : int
328 : fd_wksp_private_printf_v1( int out,
329 : char const * path,
330 0 : int verbose ) {
331 :
332 0 : # define TRAP(x) do { err = (x); if( FD_UNLIKELY( err<0 ) ) { ret = err; goto done; } ret += err; } while(0)
333 0 : # define RESTORE_TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { err_info = #c; goto stream_err; } } while(0)
334 :
335 0 : int fd = -1;
336 0 : fd_io_buffered_istream_t * restore = NULL;
337 0 : int ret = 0;
338 0 : int err;
339 0 : char const * err_info;
340 0 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
341 0 : fd_io_buffered_istream_t _restore[1];
342 :
343 0 : fd = open( path, O_RDONLY, (mode_t)0 );
344 0 : if( FD_UNLIKELY( fd==-1 ) ) TRAP( dprintf( out, "\topen(O_RDONLY) failed (%i-%s)\n", errno, fd_io_strerror( errno ) ) );
345 :
346 0 : 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 0 : ulong orig_part_max;
352 0 : ulong orig_data_max;
353 :
354 0 : {
355 0 : ulong magic; RESTORE_ULONG( magic );
356 0 : ulong style_ul; RESTORE_ULONG( style_ul );
357 0 : ulong seed_ul; RESTORE_ULONG( seed_ul );
358 0 : ulong part_max; RESTORE_ULONG( part_max );
359 0 : ulong data_max; RESTORE_ULONG( data_max );
360 0 : ulong ts_ul; RESTORE_ULONG( ts_ul ); /* considered metadata */
361 0 : ulong app_id; RESTORE_ULONG( app_id ); /* " */
362 0 : ulong thread_id; RESTORE_ULONG( thread_id ); /* " */
363 0 : ulong host_id; RESTORE_ULONG( host_id ); /* " */
364 0 : ulong cpu_id; RESTORE_ULONG( cpu_id ); /* " */
365 0 : ulong group_id; RESTORE_ULONG( group_id ); /* " */
366 0 : ulong tid; RESTORE_ULONG( tid ); /* " */
367 0 : ulong user_id; RESTORE_ULONG( user_id ); /* " */
368 :
369 0 : char name[ FD_SHMEM_NAME_MAX ]; ulong name_len; RESTORE_CSTR( name, FD_SHMEM_NAME_MAX );
370 :
371 0 : RESTORE_TEST( magic==FD_WKSP_MAGIC );
372 0 : RESTORE_TEST( style_ul==(ulong)FD_WKSP_CHECKPT_STYLE_V1 );
373 0 : RESTORE_TEST( seed_ul==(ulong)(uint)seed_ul );
374 0 : RESTORE_TEST( fd_wksp_footprint( part_max, data_max )>0UL );
375 0 : RESTORE_TEST( (name_len>0UL) & (fd_shmem_name_len( name )==name_len) );
376 :
377 0 : char app [ FD_LOG_NAME_MAX ]; ulong app_len; RESTORE_CSTR( app, FD_LOG_NAME_MAX );
378 0 : char thread[ FD_LOG_NAME_MAX ]; ulong thread_len; RESTORE_CSTR( thread, FD_LOG_NAME_MAX );
379 0 : char host [ FD_LOG_NAME_MAX ]; ulong host_len; RESTORE_CSTR( host, FD_LOG_NAME_MAX );
380 0 : char cpu [ FD_LOG_NAME_MAX ]; ulong cpu_len; RESTORE_CSTR( cpu, FD_LOG_NAME_MAX );
381 0 : char group [ FD_LOG_NAME_MAX ]; ulong group_len; RESTORE_CSTR( group, FD_LOG_NAME_MAX );
382 0 : char user [ FD_LOG_NAME_MAX ]; ulong user_len; RESTORE_CSTR( user, FD_LOG_NAME_MAX );
383 0 : char binfo [ FD_WKSP_CHECKPT_V1_BINFO_MAX ]; ulong binfo_len; RESTORE_CSTR( binfo, FD_WKSP_CHECKPT_V1_BINFO_MAX );
384 0 : char uinfo [ FD_WKSP_CHECKPT_V1_UINFO_MAX ]; ulong uinfo_len; RESTORE_CSTR( uinfo, FD_WKSP_CHECKPT_V1_UINFO_MAX );
385 :
386 0 : char ts_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ];
387 0 : fd_log_wallclock_cstr( (long)ts_ul, ts_cstr );
388 :
389 : /* Note: this mirrors v2 printf */
390 :
391 0 : if( verbose>=1 )
392 0 : 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 0 : "\tmagic %016lx\n" /* verbose 1 info */
399 0 : "\twallclock %-20li (%s)\n"
400 0 : "\tapp %-20lu (%s)\n"
401 0 : "\tthread %-20lu (%s)\n"
402 0 : "\thost %-20lu (%s)\n"
403 0 : "\tcpu %-20lu (%s)\n"
404 0 : "\tgroup %-20lu (%s)\n"
405 0 : "\ttid %-20lu\n"
406 0 : "\tuser %-20lu (%s)\n",
407 0 : magic,
408 0 : (long)ts_ul, ts_cstr,
409 0 : app_id, app,
410 0 : thread_id, thread,
411 0 : host_id, host,
412 0 : cpu_id, cpu,
413 0 : group_id, group,
414 0 : tid,
415 0 : user_id, user ) );
416 0 : if( verbose>=2 )
417 0 : TRAP( dprintf( out, "\tbinfo\n\t\t%s\n"
418 0 : "\tuinfo\n\t\t%s\n", binfo, uinfo ) ); /* verbose 2 info */
419 :
420 0 : orig_part_max = part_max;
421 0 : orig_data_max = data_max;
422 0 : }
423 :
424 0 : if( verbose>=3 ) {
425 :
426 0 : ulong orig_data_lo = fd_wksp_private_data_off( orig_part_max );
427 0 : ulong orig_data_hi = orig_data_lo + orig_data_max;
428 :
429 0 : ulong alloc_tot = 0UL;
430 0 : ulong alloc_cnt = 0UL;
431 0 : ulong alloc_big = 0UL;
432 :
433 0 : if( verbose>=4 ) TRAP( dprintf( out, "\tgaddr [0x%016lx,0x%016lx)\n", orig_data_lo, orig_data_hi ) );
434 :
435 0 : for(;;) {
436 :
437 : /* Print partition metadata */
438 :
439 0 : 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 0 : TRAP( dprintf( out, "\t%20lu bytes used (%20lu blocks, largest %20lu bytes)\n"
461 0 : "\t%20lu bytes free (%20s blocks, largest %20s bytes)\n"
462 0 : "\t%20lu errors detected\n"
463 0 : , alloc_tot, alloc_cnt, alloc_big, orig_data_max-alloc_tot, "-", "-", 0UL /* no err if we got here */ ) );
464 :
465 0 : }
466 :
467 0 : done:
468 0 : if( FD_LIKELY( restore ) ) fd_io_buffered_istream_fini( restore );
469 0 : if( FD_LIKELY( fd!=-1 ) ) close( fd ); /* TODO: Consider trapping (but we might be in a dprintf err) */
470 0 : 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
|