code wiki / (root) / nx_portcheck.nx

nx_portcheck.nx source

↩ module page · 365 lines · 19770 B

1// nx_portcheck.nx -- R1 of the sovereign-:443 arc: a SOVEREIGN "what owns this port" inspector. The deploy team 2// (nx_hostctl/nx_aw_hostctl) can start/stop/swap named daemons but has NO way to answer "what process is bound to 3// :443" -- the never-brick prerequisite before a sovereign terminator can take :443 from DSM (operator: "build them 4// up if they lack the capability, rung by rung; dont use shell"). This reads /proc sovereignly (syscalls only, no 5// ss/lsof/netstat): /proc/net/tcp{,6} for a LISTEN socket on the target port -> its inode; then /proc/<pid>/fd via 6// getdents64 + readlinkat(__syscall 267) to find the owning pid; then /proc/<pid>/comm for the process name. 7// license_tier: ORIGINAL expect_exit: 0 8import "nx_syscalls.nx" 9import "nx_os_introspect.nx" 10const PC_MAGIC_32768: i64 = 32768 11const PC_MAGIC_53991: i64 = 53991 12 13const PC_TCP_LISTEN: i64 = 0x0A 14const PC_AT_FDCWD: i64 = 0 - 100 15const PC_SYS_READLINKAT: i64 = 267 // x86_64 readlinkat(dirfd, path, buf, bufsiz) 16 17func pc_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 18func pc_row(name: *u8, ok: i64) -> i64 { if ok == 1 { pc_w(" PASS " as *u8) } else { pc_w(" FAIL " as *u8) } pc_w(name); pc_w("\n" as *u8); return ok } 19func pc_is_space(c: i64) -> i64 { if c == 32 { return 1 } if c == 9 { return 1 } return 0 } 20func pc_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 21func pc_puti(v: i64) -> i64 { var t: i64=v; if t<0 { sys_write(1,"-" as *u8,1); t=0-t } let tm: *u8=sys_mmap(24); var k: i64=0; if t==0 {tm[0]=48 as u8;k=1} while t>0 {tm[k]=(48+(t%10)) as u8;t=t/10;k=k+1} let b: *u8=sys_mmap(24); var j: i64=0; while j<k {b[j]=tm[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 22 23// parse a hex run [s,e) -> value 24func pc_hex(buf: *u8, s: i64, e: i64) -> i64 { 25 var v: i64 = 0; var i: i64 = s 26 while i < e { 27 let c: i64 = buf[i] & 0xff; var d: i64 = 0 - 1 28 if c >= 48 { if c <= 57 { d = c - 48 } } 29 if c >= 65 { if c <= 70 { d = c - 55 } } 30 if c >= 97 { if c <= 102 { d = c - 87 } } 31 if d < 0 { return v } 32 v = (v << 4) | d; i = i + 1 33 } 34 return v 35} 36// parse a decimal run [s,e) -> value 37func pc_dec(buf: *u8, s: i64, e: i64) -> i64 { 38 var v: i64 = 0; var i: i64 = s 39 while i < e { let c: i64 = buf[i] & 0xff; if c < 48 { return v } if c > 57 { return v } v = v*10 + (c-48); i = i + 1 } 40 return v 41} 42 43// field idx in [lstart,lend) (whitespace-delimited) -> sets fs/fe to its [start,end). returns 1/0. 44func pc_field(buf: *u8, lstart: i64, lend: i64, idx: i64, fs: *i64, fe: *i64) -> i64 { 45 var o: i64 = lstart; var f: i64 = 0 46 while o < lend { 47 while o < lend { if pc_is_space(buf[o] as i64) == 1 { o = o + 1 } else { break } } // skip leading spaces 48 if o >= lend { return 0 } 49 let st: i64 = o 50 while o < lend { if pc_is_space(buf[o] as i64) == 1 { break } else { o = o + 1 } } // field body 51 if f == idx { fs[0] = st; fe[0] = o; return 1 } 52 f = f + 1 53 } 54 return 0 55} 56 57// scan a /proc/net/tcp* file for a LISTEN socket on `port`; return its inode (0 = none). 58func pc_scan_file(path: *u8, port: i64) -> i64 { 59 let lb: *i64 = sys_mmap(8) as *i64 60 let data: *u8 = sys_read_file(path, lb) 61 if (data as i64) == 0 { return 0 } 62 let n: i64 = lb[0] 63 let fs: *i64 = sys_mmap(8) as *i64; let fe: *i64 = sys_mmap(8) as *i64 64 var ls: i64 = 0; var first: i64 = 1 65 while ls < n { 66 var le: i64 = ls 67 while le < n { if data[le] == (10 as u8) { break } else { le = le + 1 } } 68 if first == 1 { first = 0 } // skip the header row 69 else { if le > ls { 70 if pc_field(data, ls, le, 3, fs, fe) == 1 { // st 71 if pc_hex(data, fs[0], fe[0]) == PC_TCP_LISTEN { 72 if pc_field(data, ls, le, 1, fs, fe) == 1 { // local_address "IP:PORT" 73 var cp: i64 = fs[0] 74 while cp < fe[0] { if data[cp] == (58 as u8) { break } else { cp = cp + 1 } } // ':' 75 if cp < fe[0] { 76 if pc_hex(data, cp + 1, fe[0]) == port { 77 if pc_field(data, ls, le, 9, fs, fe) == 1 { return pc_dec(data, fs[0], fe[0]) } // inode 78 } 79 } 80 } 81 } 82 } 83 } } 84 ls = le + 1 85 } 86 return 0 87} 88// find the inode of a LISTEN socket on `port` across IPv4 + IPv6. 89func pc_listener_inode(port: i64) -> i64 { 90 let i4: i64 = pc_scan_file("/proc/net/tcp" as *u8, port) 91 if i4 > 0 { return i4 } 92 return pc_scan_file("/proc/net/tcp6" as *u8, port) 93} 94 95func pc_readlink(path: *u8, out: *u8, cap: i64) -> i64 { 96 let r: i64 = __syscall(PC_SYS_READLINKAT, PC_AT_FDCWD, path as i64, out as i64, cap, 0, 0) 97 if r < 0 { return 0 } 98 if r < cap { out[r] = 0 as u8 } 99 return r 100} 101func pc_str_all_digits(s: *u8) -> i64 { var i: i64 = 0; if s[0] == (0 as u8) { return 0 } while s[i] != (0 as u8) { let c: i64 = s[i] & 0xff; if c < 48 { return 0 } if c > 57 { return 0 } i = i + 1 } return 1 } 102func pc_join(a: *u8, b: *u8, c: *u8, d: *u8, out: *u8) -> i64 { 103 var o: i64 = 0 104 var i: i64 = 0; while a[i] != (0 as u8) { out[o] = a[i]; o = o+1; i = i+1 } 105 i = 0; while b[i] != (0 as u8) { out[o] = b[i]; o = o+1; i = i+1 } 106 i = 0; while c[i] != (0 as u8) { out[o] = c[i]; o = o+1; i = i+1 } 107 i = 0; while d[i] != (0 as u8) { out[o] = d[i]; o = o+1; i = i+1 } 108 out[o] = 0 as u8; return o 109} 110func pc_join3(a: *u8, b: *u8, c: *u8, out: *u8) -> i64 { 111 var o: i64 = 0 112 var i: i64 = 0; while a[i] != (0 as u8) { out[o]=a[i]; o=o+1; i=i+1 } 113 i=0; while b[i] != (0 as u8) { out[o]=b[i]; o=o+1; i=i+1 } 114 i=0; while c[i] != (0 as u8) { out[o]=c[i]; o=o+1; i=i+1 } 115 out[o]=0 as u8; return o 116} 117// does /proc/<piddir>/fd contain a symlink to socket:[inode]? returns 1/0. 118func pc_pid_has_inode(piddir: *u8, inode: i64) -> i64 { 119 let fdpath: *u8 = sys_mmap(256); pc_join3("/proc/" as *u8, piddir, "/fd" as *u8, fdpath) 120 let fd: i64 = sys_openat_rd(fdpath) 121 if fd < 0 { return 0 } 122 let buf: *u8 = sys_mmap(PC_MAGIC_32768); let lnk: *u8 = sys_mmap(256); let full: *u8 = sys_mmap(320) 123 var found: i64 = 0 124 var rn: i64 = sys_getdents64(fd, buf, PC_MAGIC_32768) 125 while rn > 0 { 126 var off: i64 = 0 127 while off < rn { 128 let rec: *u8 = (buf as i64 + off) as *u8 129 let nm: *u8 = dirent_name(rec) 130 if pc_str_all_digits(nm) == 1 { 131 pc_join("/proc/" as *u8, piddir, "/fd/" as *u8, nm, full) 132 let ln: i64 = pc_readlink(full, lnk, 256) 133 if ln > 8 { 134 // match "socket:[" prefix then the inode digits 135 if lnk[0]==(115 as u8) { if lnk[7]==(91 as u8) { // 's' ... '[' 136 var k: i64 = 8; while k < ln { if lnk[k] == (93 as u8) { break } else { k = k+1 } } 137 if pc_dec(lnk, 8, k) == inode { found = 1 } 138 } } 139 } 140 } 141 let rl: i64 = dirent_reclen(rec); if rl <= 0 { off = rn } else { off = off + rl } 142 } 143 if found == 1 { rn = 0 } else { rn = sys_getdents64(fd, buf, PC_MAGIC_32768) } 144 } 145 sys_close(fd) 146 return found 147} 148// scan /proc/<pid> for the process owning `inode`; return the pid (0 = none). 149func pc_inode_to_pid(inode: i64) -> i64 { 150 let fd: i64 = sys_openat_rd("/proc" as *u8) 151 if fd < 0 { return 0 } 152 let buf: *u8 = sys_mmap(PC_MAGIC_32768) 153 var pid: i64 = 0 154 var rn: i64 = sys_getdents64(fd, buf, PC_MAGIC_32768) 155 while rn > 0 { 156 var off: i64 = 0 157 while off < rn { 158 let rec: *u8 = (buf as i64 + off) as *u8 159 let nm: *u8 = dirent_name(rec) 160 if pc_str_all_digits(nm) == 1 { 161 if pc_pid_has_inode(nm, inode) == 1 { pid = pc_dec(nm, 0, pc_strlen(nm)) } 162 } 163 let rl: i64 = dirent_reclen(rec); if rl <= 0 { off = rn } else { off = off + rl } 164 } 165 if pid > 0 { rn = 0 } else { rn = sys_getdents64(fd, buf, PC_MAGIC_32768) } 166 } 167 sys_close(fd) 168 return pid 169} 170func pc_pid_comm(pid: i64, out: *u8, cap: i64) -> i64 { 171 let ps: *u8 = sys_mmap(24); var t: i64 = pid; var k: i64 = 0 172 if t == 0 { ps[0]=48 as u8; k=1 } let tmp: *u8 = sys_mmap(24) 173 while t > 0 { tmp[k] = (48 + (t%10)) as u8; t=t/10; k=k+1 } 174 var j: i64 = 0; while j < k { ps[j] = tmp[k-1-j]; j=j+1 } ps[k] = 0 as u8 175 let path: *u8 = sys_mmap(64); pc_join3("/proc/" as *u8, ps, "/comm" as *u8, path) 176 let lb: *i64 = sys_mmap(8) as *i64 177 let d: *u8 = sys_read_file(path, lb) 178 if (d as i64) == 0 { out[0]=0 as u8; return 0 } 179 var n: i64 = lb[0]; if n > 0 { if d[n-1]==(10 as u8) { n = n-1 } } 180 var i: i64 = 0; while i < n { if i < cap-1 { out[i]=d[i] } i=i+1 } out[n]=0 as u8 181 return n 182} 183 184// ===================== in-process gate: bind a listener, find it, map it to US ===================== 185func pc_legacy_gate() -> i64 { 186 pc_w("nx_portcheck gate -- sovereign 'what owns this port' via /proc (no ss/lsof/netstat); R1 sovereign-:443\n" as *u8) 187 let TESTPORT: i64 = PC_MAGIC_53991 188 189 // bind a real LISTEN socket on 127.0.0.1:TESTPORT 190 let fd: i64 = sys_socket(2, 1, 0) 191 if fd < 0 { pc_w("SOCKET FAIL\n" as *u8); sys_exit(1) } 192 let opt: *u8 = sys_mmap(4); opt[0]=1 as u8; sys_setsockopt(fd, 1, 2, opt, 4) 193 let addr: *u8 = sys_mmap(16) 194 addr[0]=2 as u8; addr[1]=0 as u8 195 addr[2]=((TESTPORT>>8)&0xff) as u8; addr[3]=(TESTPORT&0xff) as u8 196 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8 197 var z: i64=8; while z<16 { addr[z]=0 as u8; z=z+1 } 198 if sys_bind(fd, addr, 16) < 0 { pc_w("BIND FAIL\n" as *u8); sys_exit(1) } 199 if sys_listen(fd, 4) < 0 { pc_w("LISTEN FAIL\n" as *u8); sys_exit(1) } 200 201 var pass: i64 = 0 202 203 // T1: the listener is found in /proc/net/tcp with a real inode 204 let inode: i64 = pc_listener_inode(TESTPORT) 205 var t1: i64 = 0; if inode > 0 { t1 = 1 } 206 pass = pass + pc_row("T1 LISTEN socket on the test port found in /proc/net/tcp (inode resolved)" as *u8, t1) 207 208 209 // T2: the inode maps to an owning pid 210 let pid: i64 = pc_inode_to_pid(inode) 211 var t2: i64 = 0; if pid > 0 { t2 = 1 } 212 pass = pass + pc_row("T2 inode -> owning pid via /proc/*/fd readlinkat" as *u8, t2) 213 214 // T3: that pid is US (readlinkat /proc/self), i.e. the mapping is CORRECT not arbitrary 215 let selfl: *u8 = sys_mmap(64); pc_readlink("/proc/self" as *u8, selfl, 64) 216 let selfpid: i64 = pc_dec(selfl, 0, pc_strlen(selfl)) 217 var t3: i64 = 0; if pid == selfpid { if selfpid > 0 { t3 = 1 } } 218 pass = pass + pc_row("T3 owning pid == /proc/self (the mapping found THIS process, not a wrong one)" as *u8, t3) 219 220 // T4: the pid resolves to a process name 221 let comm: *u8 = sys_mmap(64); let cn: i64 = pc_pid_comm(pid, comm, 64) 222 var t4: i64 = 0; if cn > 0 { t4 = 1 } 223 pass = pass + pc_row("T4 pid -> process name via /proc/<pid>/comm" as *u8, t4) 224 225 // T5: a port with NO listener resolves to inode 0 (no false positive) 226 var t5: i64 = 0; if pc_listener_inode(TESTPORT + 1) == 0 { t5 = 1 } 227 pass = pass + pc_row("T5 an unbound port -> inode 0 (no false positive)" as *u8, t5) 228 229 pc_w(" owner: pid=" as *u8); let pb: *u8 = sys_mmap(24); var tp: i64=pid; var pk: i64=0 230 if tp==0 { pb[0]=48 as u8; pk=1 } let pt: *u8=sys_mmap(24); while tp>0 { pt[pk]=(48+(tp%10)) as u8; tp=tp/10; pk=pk+1 } 231 var pj: i64=0; while pj<pk { pb[pj]=pt[pk-1-pj]; pj=pj+1 } sys_write(1, pb, pk) 232 pc_w(" comm=" as *u8); sys_write(1, comm, cn); pc_w("\n" as *u8) 233 sys_close(fd) 234 235 if pass == 5 { 236 pc_w("NX-PORTCHECK GATE GREEN 5/5 (sovereign port->inode->pid->comm; ready to confirm who owns :443 on the NAS)\n" as *u8) 237 sys_exit(0) 238 } 239 pc_w("NX-PORTCHECK GATE RED\n" as *u8) 240 sys_exit(1) 241 return 1 242} 243 244// Additive structured observer; no registration, signal, bind or restart side effects. 245const PCL_EXIT_USAGE: i64 = 3 246const PCL_EXIT_OUTPUT: i64 = 4 247const PCL_INTEGER_BYTES: i64 = 21 248const PCL_I64_MIN: i64 = 0-9223372036854775807-1 249static pcl_output_failed: i64 250 251func pcl_raw(s: *u8, n: i64) -> i64 { 252 if pcl_output_failed != 0 { return 0-1 } 253 var done: i64=0 254 while done < n { 255 let wrote: i64=sys_write(1,((s as i64)+done) as *u8,n-done) 256 if wrote <= 0 { pcl_output_failed=1; return 0-1 } 257 done=done+wrote 258 }; return 0 259} 260func pcl_text(s: *u8) -> i64 { return pcl_raw(s,pc_strlen(s)) } 261func pcl_number(value: i64) -> i64 { 262 if value == PCL_I64_MIN { return pcl_text("-9223372036854775808" as *u8) } 263 let out: *u8=sys_mmap(PCL_INTEGER_BYTES) 264 if (out as i64) <= 0 { pcl_output_failed=1; return 0-1 } 265 var n: i64=0; var magnitude: i64=value 266 if magnitude < 0 { out[0]=45 as u8; n=1; magnitude=0-magnitude } 267 n=pon_obs_number(out,n,magnitude) 268 let result: i64=pcl_raw(out,n); sys_munmap(out,PCL_INTEGER_BYTES); return result 269} 270func pcl_equal(a: *u8, b: *u8) -> i64 { 271 var i: i64=0 272 while a[i] == b[i] { if a[i] == (0 as u8) { return 1 }; i=i+1 }; return 0 273} 274func pcl_status(status: i64) -> *u8 { 275 if status == PON_OBS_COMPLETE { return "COMPLETE" as *u8 } 276 if status == PON_OBS_UNKNOWN { return "UNKNOWN" as *u8 } 277 if status == PON_OBS_CAPACITY { return "CAPACITY" as *u8 } 278 return "BAD_INPUT" as *u8 279} 280func pcl_stage(stage: i64) -> *u8 { 281 if stage == PON_L_STAGE_INPUT { return "input" as *u8 } 282 if stage == PON_L_STAGE_OPEN { return "open" as *u8 } 283 if stage == PON_L_STAGE_READ { return "read" as *u8 } 284 if stage == PON_L_STAGE_PARSE { return "parse" as *u8 } 285 if stage == PON_L_STAGE_ROWS { return "rows" as *u8 } 286 if stage == PON_L_STAGE_CLOSE { return "close" as *u8 } 287 if stage == PON_L_STAGE_ALLOC { return "allocation" as *u8 } 288 return "none" as *u8 289} 290func pcl_refuse(code: *u8) -> i64 { 291 // `code` is always a literal chosen below; no untrusted argument is interpolated. 292 pcl_text("{\"schema\":\"nishi.port-listeners\",\"v\":1,\"status\":\"BAD_INPUT\",\"complete\":false,\"error\":{\"code\":\"" as *u8) 293 pcl_text(code) 294 pcl_text("\",\"stage\":\"input\"},\"usage\":\"nx_portcheck listeners <port> <row_capacity> <read_capacity_bytes>\",\"rows\":[]}\n" as *u8) 295 if pcl_output_failed != 0 { return PCL_EXIT_OUTPUT }; return PCL_EXIT_USAGE 296} 297func pcl_emit(port: i64, row_capacity: i64, read_capacity: i64, rows: *i64, addresses: *u8, st: *i64, begin: i64, end: i64) -> i64 { 298 let status: i64=st[PON_L_STATUS] 299 pcl_text("{\"schema\":\"nishi.port-listeners\",\"v\":1,\"status\":\"" as *u8); pcl_text(pcl_status(status)) 300 pcl_text("\",\"complete\":" as *u8) 301 if status == PON_OBS_COMPLETE { pcl_text("true" as *u8) } else { pcl_text("false" as *u8) } 302 pcl_text(",\"error\":" as *u8) 303 if status == PON_OBS_COMPLETE { pcl_text("null" as *u8) } else { 304 pcl_text("{\"code\":\"" as *u8); pcl_text(pcl_status(status)); pcl_text("\",\"first_native_error\":" as *u8); pcl_number(st[PON_L_FIRST_ERROR]) 305 pcl_text(",\"first_stage\":\"" as *u8); pcl_text(pcl_stage(st[PON_L_FIRST_STAGE])); pcl_text("\",\"count\":" as *u8); pcl_number(st[PON_L_ERRORS]); pcl_text("}" as *u8) 306 } 307 pcl_text(",\"request\":{\"port\":" as *u8); pcl_number(port); pcl_text(",\"row_capacity\":" as *u8); pcl_number(row_capacity) 308 pcl_text(",\"read_capacity_bytes_per_file\":" as *u8); pcl_number(read_capacity); pcl_text("}" as *u8) 309 pcl_text(",\"evidence\":{\"observer\":\"nx_os_introspect.pon_observe_listeners\",\"scope\":\"tcp_listen_rows_in_current_network_namespace\",\"sources\":[\"/proc/net/tcp\",\"/proc/net/tcp6\"],\"atomic_snapshot\":false,\"process_identity_verified\":false,\"restart_authority\":false,\"observation_start_unix\":" as *u8) 310 if begin > 0 { pcl_number(begin) } else { pcl_text("null" as *u8) } 311 pcl_text(",\"observation_end_unix\":" as *u8) 312 if end > 0 { pcl_number(end) } else { pcl_text("null" as *u8) } 313 pcl_text(",\"clock\":\"realtime_seconds\",\"fully_read_files\":" as *u8); pcl_number(st[PON_L_FILES_COMPLETE]) 314 pcl_text(",\"bytes_read\":" as *u8); pcl_number(st[PON_L_BYTES]); pcl_text(",\"data_rows_examined\":" as *u8); pcl_number(st[PON_L_ROWS]); pcl_text("}" as *u8) 315 pcl_text(",\"matching_rows\":" as *u8); pcl_number(st[PON_L_MATCHES]); pcl_text(",\"returned_rows\":" as *u8); pcl_number(st[PON_L_STORED]) 316 pcl_text(",\"address_encoding\":\"linux_proc_net_tcp_kernel_hex_not_normalized_ip\",\"rows\":[" as *u8) 317 var i: i64=0 318 while i < st[PON_L_STORED] { 319 if i > 0 { pcl_text("," as *u8) } 320 let r: i64=i*PON_L_ROW_SLOTS 321 pcl_text("{\"family\":\"" as *u8) 322 if rows[r+PON_L_FAMILY] == PON_L_FAMILY4 { pcl_text("ipv4" as *u8) } else { pcl_text("ipv6" as *u8) } 323 pcl_text("\",\"port\":" as *u8); pcl_number(rows[r+PON_L_PORT]); pcl_text(",\"inode\":" as *u8); pcl_number(rows[r+PON_L_INODE]) 324 // The shared parser proved this span contains only exactly8/32 hex bytes. 325 pcl_text(",\"address_hex\":\"" as *u8); pcl_raw(((addresses as i64)+i*PON_L_ADDRESS_STRIDE) as *u8,rows[r+PON_L_ADDRESS_N]); pcl_text("\"}" as *u8) 326 i=i+1 327 } 328 pcl_text("]}\n" as *u8) 329 if pcl_output_failed != 0 { return PCL_EXIT_OUTPUT } 330 return status 331} 332func pcl_listeners(argc: i64, argv: *i64) -> i64 { 333 pcl_output_failed=0 334 if argc != 5 { return pcl_refuse("usage_listeners" as *u8) } 335 let port: i64=pon_obs_uint(argv[2] as *u8,0,pc_strlen(argv[2] as *u8)) 336 let row_capacity: i64=pon_obs_uint(argv[3] as *u8,0,pc_strlen(argv[3] as *u8)) 337 let read_capacity: i64=pon_obs_uint(argv[4] as *u8,0,pc_strlen(argv[4] as *u8)) 338 if port <= 0 || port > PON_L_PORT_MAX { return pcl_refuse("invalid_port" as *u8) } 339 if row_capacity < 0 || row_capacity > PON_OBS_I64_MAX/PON_L_ADDRESS_STRIDE || row_capacity > PON_OBS_I64_MAX/(PON_L_ROW_SLOTS*PON_OBS_I64_BYTES) { return pcl_refuse("invalid_row_capacity" as *u8) } 340 if read_capacity <= 0 || read_capacity >= PON_OBS_I64_MAX/2 { return pcl_refuse("invalid_read_capacity" as *u8) } 341 let st: *i64=sys_mmap(PON_L_STATE_SLOTS*PON_OBS_I64_BYTES) as *i64 342 if (st as i64) <= 0 { pcl_text("{\"schema\":\"nishi.port-listeners\",\"v\":1,\"status\":\"UNKNOWN\",\"complete\":false,\"error\":{\"code\":\"allocation_failed\",\"stage\":\"allocation\"},\"rows\":[]}\n" as *u8); if pcl_output_failed != 0 { return PCL_EXIT_OUTPUT }; return PON_OBS_UNKNOWN } 343 pon_listener_init(st) 344 var rows: *i64=0 as *i64; var addresses: *u8=0 as *u8 345 if row_capacity > 0 { 346 rows=sys_mmap(row_capacity*PON_L_ROW_SLOTS*PON_OBS_I64_BYTES) as *i64 347 addresses=sys_mmap(row_capacity*PON_L_ADDRESS_STRIDE) 348 } 349 let begin: i64=sys_now_realtime_sec() 350 if row_capacity > 0 && ((rows as i64) <= 0 || (addresses as i64) <= 0) { 351 pon_listener_error(st,PON_L_STAGE_ALLOC,PON_OBS_E_ALLOC,0) 352 } else { pon_observe_listeners(port,rows,addresses,row_capacity,read_capacity,st) } 353 let end: i64=sys_now_realtime_sec() 354 let result: i64=pcl_emit(port,row_capacity,read_capacity,rows,addresses,st,begin,end) 355 if (rows as i64) > 0 { sys_munmap(rows as *u8,row_capacity*PON_L_ROW_SLOTS*PON_OBS_I64_BYTES) } 356 if (addresses as i64) > 0 { sys_munmap(addresses,row_capacity*PON_L_ADDRESS_STRIDE) } 357 sys_munmap(st as *u8,PON_L_STATE_SLOTS*PON_OBS_I64_BYTES) 358 return result 359} 360func main(argc: i64, argv: *i64) -> i64 { 361 if argc == 1 { return pc_legacy_gate() } 362 if sys_ignore_sigpipe() != 0 { return PCL_EXIT_OUTPUT } 363 if argc > 1 { if pcl_equal(argv[1] as *u8,"listeners" as *u8) == 1 { return pcl_listeners(argc,argv) } } 364 pcl_output_failed=0; return pcl_refuse("unknown_command" as *u8) 365}