code wiki / _hdl_build / nx_mgmt_snapshot_run.nx
nx_mgmt_snapshot_run.nx source
↩ module page · 274 lines · 11642 B
1// nx_mgmt_snapshot_run.nx -- the COMPLETE, self-contained health-snapshot PRODUCER binary (R1b, live path).
2// Scans /proc ITSELF (sys_getdents64) -> reads each pid's stat+cmdline -> classifies procs against a data-driven
3// service table -> counts crash-loop restarts from the supervisor.log -> composes the two ALREADY-GATED tiers
4// (nx_snapfeed sf_* parse + nx_mgmt_snapshot ss_synth) -> writes the canonical SUP/SVC snapshot the mgmt API
5// reads (mgmt_snap.json). This needs NO nx_hostctl edit: it is one binary you run (or later supervise/pulse).
6// Because it reads REAL /proc, it is validated end-to-end on real kernel data (WSL /proc locally; NAS /proc live).
7//
8// Correctness lessons carried through: services are matched by their FULL /proc/<pid>/cmdline (never the 15-char
9// comm -- the gallery-disaster anti-truncation lesson); supervisor lineage = session-leaders (pid==sid) via
10// ss_synth, so the reader-keeper child is not a false 2nd supervisor.
11//
12// argv: [1]=services.conf [2]=supervisor.log [3]=out snapfile
13// services.conf rows: <canon> <port> <cmdline-match> ('#' = comment) e.g. sites 8443 nx_sites_daemon
14// license_tier: ORIGINAL
15import "nx_mgmt_snapshot.nx"
16import "nx_snapfeed.nx"
17import "nx_syscalls.nx"
18const MSR_MAGIC_262144: i64 = 262144
19const MSR_MAGIC_1024: i64 = 1024
20const MSR_MAGIC_4096: i64 = 4096
21const MSR_MAGIC_65536: i64 = 65536
22const MSR_MAGIC_4095: i64 = 4095
23
24const MSR_MAXSVC: i64 = 64
25const MSR_MAXP: i64 = 4096
26
27func msr_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
28func msr_wn(v0: i64) -> i64 {
29 var v: i64 = v0
30 if v < 0 { msr_w("-" as *u8); v = 0 - v }
31 if v == 0 { msr_w("0" as *u8); return 0 }
32 let t: *u8 = sys_mmap(32)
33 var k: i64 = 0
34 while v > 0 { let d: i64 = v - (v / 10) * 10; t[k] = (d + 48) as u8; v = v / 10; k = k + 1 }
35 let r: *u8 = sys_mmap(32)
36 var w: i64 = 0
37 while k > 0 { k = k - 1; r[w] = t[k]; w = w + 1 }
38 r[w] = 0 as u8
39 msr_w(r)
40 return 0
41}
42
43// is a dirent name all-digits (a pid dir)?
44func msr_is_pid(name: *u8) -> i64 {
45 if name[0] == (0 as u8) { return 0 }
46 var i: i64 = 0
47 while name[i] != (0 as u8) {
48 let c: i64 = name[i] as i64
49 if c < 48 { return 0 }
50 if c > 57 { return 0 }
51 i = i + 1
52 }
53 return 1
54}
55
56// copy src[off..off+len) into dst as a NUL-terminated string.
57func msr_copyz(dst: *u8, src: *u8, off: i64, len: i64) -> i64 {
58 var i: i64 = 0
59 while i < len { dst[i] = src[off + i]; i = i + 1 }
60 dst[len] = 0 as u8
61 return len
62}
63
64// read a small /proc file fully into buf (cap). returns byte count.
65func msr_read_small(path: *u8, buf: *u8, cap: i64) -> i64 {
66 let fd: i64 = sys_openat_rd(path)
67 if fd < 0 { return 0 }
68 var total: i64 = 0
69 var go: i64 = 1
70 while go == 1 {
71 let r: i64 = sys_read(fd, (((buf as i64) + total) as *u8), cap - total)
72 if r <= 0 { go = 0 } else { total = total + r; if total >= cap { go = 0 } }
73 }
74 sys_close(fd)
75 return total
76}
77
78// build "/proc/<name><suffix>" NUL-terminated into dst.
79func msr_build_path(dst: *u8, name: *u8, suffix: *u8) -> i64 {
80 var o: i64 = ss_cat(dst, 0, "/proc/" as *u8)
81 var i: i64 = 0
82 while name[i] != (0 as u8) { dst[o] = name[i]; o = o + 1; i = i + 1 }
83 o = ss_cat(dst, o, suffix)
84 dst[o] = 0 as u8
85 return o
86}
87
88// a supervisor proc = its cmdline carries both nx_hostctl AND supervise (covers the supervisor + its keeper child).
89func msr_is_sup(cmd: *u8, n: i64) -> i64 {
90 if sf_contains(cmd, n, "nx_hostctl" as *u8) == 1 {
91 if sf_contains(cmd, n, "supervise" as *u8) == 1 { return 1 }
92 }
93 return 0
94}
95
96// is matched-proc idx a real INSTANCE (a listener), or a fork-per-connection CHILD? setsid-independent:
97// a proc is a CHILD iff its parent (ppid) is another matched proc of the SAME service (canon) -- i.e. it was
98// forked by that service's listener. Two genuine duplicate listeners are both parented by the SUPERVISOR (not by
99// each other), so both count as instances -> a real `dup` is still flagged; conn-children are filtered out.
100func msr_is_instance(idx: i64, mp_pid: *i64, mp_ppid: *i64, mp_canon: *i64, nmp: i64) -> i64 {
101 let myppid: i64 = mp_ppid[idx]
102 let myc: i64 = mp_canon[idx]
103 var j: i64 = 0
104 while j < nmp {
105 if j != idx { if mp_canon[j] == myc { if mp_pid[j] == myppid { return 0 } } }
106 j = j + 1
107 }
108 return 1
109}
110
111func main(argc: i64, argv: *i64) -> i64 {
112 if argc < 4 {
113 msr_w("usage: nx_mgmt_snapshot_run <services.conf> <supervisor.log> <out-snapfile>\n" as *u8)
114 return 1
115 }
116 let svc_conf: *u8 = argv[1] as *u8
117 let sup_log: *u8 = argv[2] as *u8
118 let out_snap: *u8 = argv[3] as *u8
119
120 // ---- load the data-driven service table (canon/port/match) ----
121 let cbox: *i64 = sys_mmap(8) as *i64
122 let cfg: *u8 = sys_read_file(svc_conf, cbox)
123 if (cfg as i64) == 0 { msr_w("FATAL: cannot read services.conf\n" as *u8); return 2 }
124 let cfgn: i64 = cbox[0]
125 let svc_canon: *i64 = sys_mmap(MSR_MAXSVC * 8) as *i64
126 let svc_match: *i64 = sys_mmap(MSR_MAXSVC * 8) as *i64
127 let svc_port: *i64 = sys_mmap(MSR_MAXSVC * 8) as *i64
128 var nsvc: i64 = 0
129 let offs: *i64 = sys_mmap(64) as *i64
130 let lens: *i64 = sys_mmap(64) as *i64
131 var cur: i64 = 0
132 while cur < cfgn {
133 let le: i64 = ss_eol(cfg, cfgn, cur)
134 if le > cur { if (cfg[cur] as i64) != 35 {
135 let nf: i64 = ss_split(cfg, cur, le, offs, lens, 8)
136 if nf >= 3 { if nsvc < MSR_MAXSVC {
137 let cb: *u8 = sys_mmap(64)
138 let mb: *u8 = sys_mmap(128)
139 msr_copyz(cb, cfg, offs[0], lens[0])
140 msr_copyz(mb, cfg, offs[2], lens[2])
141 svc_canon[nsvc] = cb as i64
142 svc_match[nsvc] = mb as i64
143 svc_port[nsvc] = ss_atoi(cfg, offs[1], lens[1])
144 nsvc = nsvc + 1
145 } }
146 } }
147 cur = le + 1
148 }
149
150 // ---- read the supervisor.log (for crash-loop restart counts); tolerate absence ----
151 let lbox: *i64 = sys_mmap(8) as *i64
152 let logbuf: *u8 = sys_read_file(sup_log, lbox)
153 var logn: i64 = 0
154 if (logbuf as i64) != 0 { logn = lbox[0] }
155
156 // ---- build the FEED: SVCPORT (declarations) + PROC (from /proc scan) + RESTART (from the log) ----
157 let feed: *u8 = sys_mmap(MSR_MAGIC_262144)
158 var fo: i64 = 0
159 var s: i64 = 0
160 while s < nsvc {
161 fo = ss_cat(feed, fo, "SVCPORT " as *u8)
162 fo = ss_cat(feed, fo, (svc_canon[s]) as *u8)
163 fo = ss_cat(feed, fo, " " as *u8)
164 fo = ss_catn(feed, fo, svc_port[s])
165 fo = ss_cat(feed, fo, "\n" as *u8)
166 s = s + 1
167 }
168
169 // ---- scan /proc ----
170 let box3: *i64 = sys_mmap(32) as *i64
171 let statbuf: *u8 = sys_mmap(MSR_MAGIC_1024)
172 let cmdbuf: *u8 = sys_mmap(MSR_MAGIC_4096)
173 let pathbuf: *u8 = sys_mmap(256)
174 let dbuf: *u8 = sys_mmap(MSR_MAGIC_65536)
175 var scanned: i64 = 0
176 var matched: i64 = 0
177 let mp_pid: *i64 = sys_mmap(MSR_MAXP * 8) as *i64
178 let mp_ppid: *i64 = sys_mmap(MSR_MAXP * 8) as *i64
179 let mp_sid: *i64 = sys_mmap(MSR_MAXP * 8) as *i64
180 let mp_canon: *i64 = sys_mmap(MSR_MAXP * 8) as *i64
181 var nmp: i64 = 0
182 let dfd: i64 = sys_openat_rd("/proc" as *u8)
183 if dfd < 0 { msr_w("FATAL: cannot open /proc\n" as *u8); return 3 }
184 var go: i64 = 1
185 while go == 1 {
186 let got: i64 = sys_getdents64(dfd, dbuf, MSR_MAGIC_65536)
187 if got <= 0 { go = 0 } else {
188 var pos: i64 = 0
189 while pos < got {
190 let rec: *u8 = (((dbuf as i64) + pos) as *u8)
191 let rl: i64 = dirent_reclen(rec)
192 let nm: *u8 = dirent_name(rec)
193 if msr_is_pid(nm) == 1 {
194 scanned = scanned + 1
195 msr_build_path(pathbuf, nm, "/stat" as *u8)
196 let sn: i64 = msr_read_small(pathbuf, statbuf, 1023)
197 if sn > 0 {
198 if sf_parse_stat(statbuf, sn, box3) == 1 {
199 msr_build_path(pathbuf, nm, "/cmdline" as *u8)
200 let cn: i64 = msr_read_small(pathbuf, cmdbuf, MSR_MAGIC_4095)
201 var canon_i: i64 = 0 - 1
202 var is_sup: i64 = 0
203 if cn > 0 {
204 if msr_is_sup(cmdbuf, cn) == 1 { is_sup = 1 } else {
205 var j: i64 = 0
206 while j < nsvc {
207 if sf_contains(cmdbuf, cn, (svc_match[j]) as *u8) == 1 { canon_i = j; j = nsvc } else { j = j + 1 }
208 }
209 }
210 }
211 if is_sup == 1 {
212 fo = ss_cat(feed, fo, "PROC " as *u8)
213 fo = ss_catn(feed, fo, box3[0]); fo = ss_cat(feed, fo, " " as *u8)
214 fo = ss_catn(feed, fo, box3[1]); fo = ss_cat(feed, fo, " " as *u8)
215 fo = ss_catn(feed, fo, box3[2]); fo = ss_cat(feed, fo, " supervisor\n" as *u8)
216 matched = matched + 1
217 } else { if canon_i >= 0 {
218 if nmp < MSR_MAXP {
219 mp_pid[nmp] = box3[0]; mp_ppid[nmp] = box3[1]; mp_sid[nmp] = box3[2]; mp_canon[nmp] = canon_i
220 nmp = nmp + 1
221 }
222 } }
223 }
224 }
225 }
226 if rl <= 0 { pos = got } else { pos = pos + rl }
227 }
228 }
229 }
230 sys_close(dfd)
231
232 // ---- emit ONLY instance (listener) service procs -- filter fork-per-conn children (the adapter contract) ----
233 var mi: i64 = 0
234 while mi < nmp {
235 if msr_is_instance(mi, mp_pid, mp_ppid, mp_canon, nmp) == 1 {
236 fo = ss_cat(feed, fo, "PROC " as *u8)
237 fo = ss_catn(feed, fo, mp_pid[mi]); fo = ss_cat(feed, fo, " " as *u8)
238 fo = ss_catn(feed, fo, mp_ppid[mi]); fo = ss_cat(feed, fo, " " as *u8)
239 fo = ss_catn(feed, fo, mp_sid[mi]); fo = ss_cat(feed, fo, " " as *u8)
240 fo = ss_cat(feed, fo, (svc_canon[mp_canon[mi]]) as *u8); fo = ss_cat(feed, fo, "\n" as *u8)
241 matched = matched + 1
242 }
243 mi = mi + 1
244 }
245
246 // ---- RESTART lines: one per counted guard-restart of each service in the log window ----
247 s = 0
248 while s < nsvc {
249 var rc: i64 = 0
250 if logn > 0 { rc = sf_count_restarts(logbuf, logn, (svc_match[s]) as *u8) }
251 var t: i64 = 0
252 while t < rc {
253 fo = ss_cat(feed, fo, "RESTART " as *u8)
254 fo = ss_cat(feed, fo, (svc_canon[s]) as *u8)
255 fo = ss_cat(feed, fo, "\n" as *u8)
256 t = t + 1
257 }
258 s = s + 1
259 }
260
261 // ---- synth the snapshot (the gated ss_synth) + write it ----
262 let snapout: *u8 = sys_mmap(MSR_MAGIC_65536)
263 let snapn: i64 = ss_synth(feed, fo, snapout)
264 let wfd: i64 = sys_openat_wr(out_snap, 0x1a4)
265 if wfd < 0 { msr_w("FATAL: cannot write snapfile\n" as *u8); return 4 }
266 sys_write(wfd, snapout, snapn)
267 sys_close(wfd)
268
269 msr_w("snapshot produced: services=" as *u8); msr_wn(nsvc)
270 msr_w(" pids_scanned=" as *u8); msr_wn(scanned)
271 msr_w(" procs_matched=" as *u8); msr_wn(matched)
272 msr_w(" -> wrote " as *u8); msr_w(out_snap); msr_w(" (" as *u8); msr_wn(snapn); msr_w(" bytes)\n" as *u8)
273 return 0
274}