python3 -c "
import struct

with open('/dev/nbd0','rb') as f:
    f.seek(1024)
    sb = f.read(1024)

# Print all key superblock fields
fields = [
    ('inodes_count',        0,   'I'),
    ('blocks_count_lo',     4,   'I'),
    ('free_blocks_lo',      12,  'I'),
    ('free_inodes',         16,  'I'),
    ('first_data_block',    20,  'I'),
    ('log_block_size',      24,  'I'),  # bsize = 1024 << log_block_size
    ('blocks_per_group',    32,  'I'),  # NOTE: offset 32 not 40
    ('inodes_per_group',    40,  'I'),  # NOTE: offset 40
    ('magic',               56,  'H'),
    ('state',               58,  'H'),
    ('inode_size',          88,  'H'),
    ('block_group_nr',      90,  'H'),
    ('feat_compat',         92,  'I'),
    ('feat_incompat',       96,  'I'),
    ('feat_ro_compat',      100, 'I'),
    ('journal_inum',        180, 'I'),
    ('blocks_per_group_2',  32,  'I'),
    ('desc_size',           254, 'H'),  # GDT entry size
    ('blocks_count_hi',     336, 'I'),
]

print('Superblock fields:')
for name, off, fmt in fields:
    size = struct.calcsize('<'+fmt)
    val  = struct.unpack_from('<'+fmt, sb, off)[0]
    print(f'  {name:25s} @ offset {off:3d}: {val}')

# Recalculate key values
log_bsize = struct.unpack_from('<I', sb, 24)[0]
bsize = 1024 << log_bsize
bpg   = struct.unpack_from('<I', sb, 32)[0]
ipg   = struct.unpack_from('<I', sb, 40)[0]
desc_size = struct.unpack_from('<H', sb, 254)[0]
total_blocks_lo = struct.unpack_from('<I', sb, 4)[0]
total_blocks_hi = struct.unpack_from('<I', sb, 336)[0]
total_blocks = (total_blocks_hi << 32) | total_blocks_lo
num_groups = (total_blocks + bpg - 1) // bpg

print()
print(f'Computed values:')
print(f'  block size:     {bsize}')
print(f'  blocks/group:   {bpg}')
print(f'  inodes/group:   {ipg}')
print(f'  GDT entry size: {desc_size}')
print(f'  total blocks:   {total_blocks}')
print(f'  num groups:     {num_groups}')
print(f'  GDT size:       {num_groups * desc_size} bytes')
"
