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}