1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Handler for `trusty-memory port` — report where the daemon can be reached.
//!
//! Why: operators and agents need the daemon's address as a first-class CLI
//! surface (#526). Until #6286 that address was a TCP port picked out of
//! 7070–7079 and published in an `http_addr` file, and this command read that
//! file. ADR-0032 retired both: there is no listener to hold a port, nothing
//! writes the file, and `read_daemon_addr("trusty-memory")` therefore answers
//! `None` on every machine forever — so the command exited 1 reporting "no
//! daemon running" whether or not one was.
//!
//! What: reports the Unix socket the daemon binds — derived by
//! `trusty_common::daemon_socket_path`, the same call the daemon itself makes,
//! so caller and daemon compute the same path with nothing published between
//! them. Three formats, keeping the flags' audiences:
//! - default: the socket path → `/…/trusty-memory.sock\n`
//! - `--addr`: the same path, for a client that dials it
//! - `--json`: `{"socket":"/…/trusty-memory.sock","serving":true}\n`
//!
//! **There is no port to print, and the command does not invent one.** The
//! `--port` shape a shell substitution used to interpolate into a URL has no
//! honest value now; printing the socket is what a caller can actually use.
//!
//! Every intentional output goes to **stdout**; errors go to **stderr**. The
//! exit contract is unchanged: when nothing is serving the socket, the command
//! exits non-zero so `$(trusty-memory port)` fails cleanly rather than
//! interpolating a path to a dead endpoint.
//!
//! Test: `format_socket_output_renders_each_format`,
//! `format_socket_output_escapes_an_awkward_path`. The exit arms call
//! `process::exit` and are covered by the manual `trusty-memory port` run
//! rather than in-process — a test cannot observe an exit it shares.
use Path;
use Duration;
use Result;
/// How long to wait for the socket to prove it is being served.
///
/// A local dial either connects or is refused immediately; the budget only
/// covers a loaded machine.
const PROBE_TIMEOUT: Duration = from_millis;
/// Output format requested by the caller.
///
/// Why: the shapes have distinct audiences — a bare path for shell
/// substitution, and JSON for a scripted consumer that also wants the liveness
/// verdict without re-probing.
/// What: `Port` and `Addr` both render the socket path, because since #6286
/// there is one address and it is not a port. They are kept distinct so the
/// existing flags stay accepted rather than becoming an unknown-argument error
/// in someone's script.
/// Test: `format_socket_output_*`.
/// Render the socket for output in the requested format.
///
/// Why: separating the formatting from the I/O lets a unit test assert the
/// output without binding a socket.
/// What: the path for `Port`/`Addr`; a JSON object carrying the path and the
/// liveness verdict for `Json`. `serde_json` does the escaping, so a data
/// directory containing a quote or a backslash cannot produce invalid JSON.
/// Test: `format_socket_output_renders_each_format`.
/// Entry point for `trusty-memory port [--json | --addr]`.
///
/// Why: exposes the daemon's address so a caller does not have to re-derive the
/// socket path from the data directory.
///
/// # Errors
///
/// Never returns `Err` — an unresolvable data directory and a socket nothing is
/// serving both print to stderr and exit 1, which is what a shell substitution
/// has to see.
///
/// Test: the formatting is covered by `format_socket_output_renders_each_format`;
/// the exit arms are exercised manually (see the module doc).
pub async