Skip to main content

from_legacy_backend_json

Function from_legacy_backend_json 

Source
pub fn from_legacy_backend_json(json: &str) -> Result<Config, Error>
Expand description

Parses JSON written by to_legacy_backend_json, or any JSON in the form a serialized Config had before Config::backend existed, and recovers Config::backend from the fifteen legacy backend keys.

The keys are read exactly as they were read while each was a Config field: a key that is absent takes the default that field had, and a key of the wrong type fails the parse. Each key then supplies every capability that replaced a read of it, so a decoded configuration behaves as the same JSON did before:

  • discover_live_file_metadata supplies the three descriptor and loopback facts that were each a read of it;
  • backend_is_kvm supplies the two behaviours it selected that remain capabilities, provides_process_signal_control and emulates_child_waits (the other three are now answered by the backend itself: refusing a non-leader exec is a typed refusal it reports per exec, the gettimeofday repair runs on every backend through its time(2) probe and Guest::storable_memory_ranges, and the user address limit is each guest’s own Guest::user_address_limit report);
  • every other key supplies the one capability of the same meaning.

backend_supports_madvise supplies no capability any more: it said the tool could forward every madvise advice to the backend, which every backend now accepts, refusing an advice it does not implement itself. Since supports_madv_dontneed was deleted, MADV_DONTNEED had been forwarded whatever this key said.

This inverts to_legacy_backend_json for every capability value the keys can express, which includes every backend’s own constant except for capabilities added after the legacy form froze: those never enter it, as record_host_inputs does not, and read back as their default. There are thirteen. process_exits_complete_asynchronously and virtualizes_guest_sigalrm are true only for in-guest LiteInst, which never travels through this DBT-only form. supports_blocked_wait_signal_interruption, delivers_preemption_timer_events and runs_guest_code_between_injections read back as false, the value DBT has and the value their earlier Config fields read back as; so do reports_sigreturns and the four capabilities split out of supports_blocked_wait_signal_interruption (kernel_signal_state_is_guests, kernel_signal_targets_are_predictable, host_task_reads_reach_guest_threads, host_timed_signals_are_physical), false for DBT too. provides_guest_backtraces reads back as true, the ptrace value it takes from the starting constant and DBT’s value; the two backends that report false (in-guest LiteInst and KVM) travel through this form only inside the versioned envelope. places_orphans reads back as false and publishable_parent_death_signals as the empty set, DBT’s values; KVM, the one backend that reports otherwise, travels through this form only inside the versioned envelope too.

cpuid_virtualized_by_backend supplies no capability either: it said the backend installed a CPUID policy of its own, which no backend does any more (KVM stopped with Reverie 0f4d8852). It is still written, as false, so the legacy form keeps its bytes, and an input that says true fails the parse rather than being read as a policy no backend has.

backend_defers_vfork_child_registration supplies no capability either: it said the backend registered a vfork child only after the parent’s call returned, which Reverie’s backend contract now allows of every backend. It is written as false, its value on DBT, so the legacy form keeps its bytes. The reader still takes it as one of the fifteen keys, so it keeps its position in the array form, must be a boolean and may appear once, and ignores its value (KVM wrote true).

backend_supports_madvise is written as true, its value on DBT, so the legacy form keeps its bytes. The reader still takes it as one of the fifteen keys, so it keeps its position in the array form, must be a boolean and may appear once, and ignores its value (KVM wrote false).

syscall_clobbers_virtualized_by_backend supplies no capability either: it said the backend left the registers a syscall instruction clobbers as a native return would, which Reverie’s backend contract now requires of every backend (with the exceptions that contract names). It is written as false, its value on DBT, so the legacy form keeps its bytes. The reader still takes it as one of the fifteen keys, so it keeps its position in the array form, must be a boolean and may appear once, and ignores its value (SaBRe and KVM wrote true).

backend_virtualizes_capability_prctls supplies no capability either: it said the backend answered the capability-set prctls itself, and every backend now passes them to the kernel. It is written as false, so the legacy form keeps its bytes, and true fails the parse.

kvm_shared_dequeue_timers supplies no capability. It was read into a Config field that chose the controlled signal path, and that choice is now made from the capabilities, Config::sequentialize_threads and the control the backend offers. It is read as it was, a boolean that is false when absent, and the parse then fails unless it equals backend_is_kvm && sequentialize_threads, the value the production launcher always wrote. An accepted input whose capabilities are those of the backend that runs it selects the path it selected before. An input that would select another, such as true without backend_is_kvm, or absent beside backend_is_kvm and sequentialized threads, fails the parse rather than being silently reinterpreted. (backend_is_kvm given to a backend that offers no control, such as DBT, already misdescribed that backend and stays outside this guarantee; the production launcher never writes it.) A failed parse is handled like any malformed value: the DBT standalone JSON reader falls back to its strict default configuration and emits its could not parse HERMIT_DBT_DETCONFIG warning.

Everything else is read as the legacy form was read, by Config’s own derived deserializer with the legacy keys taken out before it sees them:

  • In an object, a key the legacy form did not name is ignored, whatever its value. backend is such a key, so it is ignored rather than read as the field it is now; no production writer emits it. A key the legacy form named fails the parse when it appears twice or holds the wrong type.
  • A JSON array lists the fields by position, as serde reads any derived struct. The positions are those of the legacy form, which are the key order of to_legacy_backend_json: the fifteen legacy keys stand where Config::backend stands. Too many elements fail the parse; too few leave the fields after them missing, each taking its default or failing the parse as the derived deserializer decides for that field.