nx_env.nx source
↩ module page · 116 lines · 4170 B
1// nx_env.nx -- environment variable lookup over the System V envp.
2//
3// At program entry the kernel hands us argc + argv + envp. envp is
4// a NULL-terminated array of "KEY=VALUE" strings. This module
5// searches envp for a given key and returns the value pointer (NUL-
6// terminated) or NULL.
7//
8// Callers (toolchain): NX_NXC_PATH, NX_DEBUG, HOME, PATH, etc.
9//
10// We don't mutate envp -- this is a pure read interface. Setenv
11// would require redirecting stdlib calls, which the off-C runtime
12// doesn't have anyway.
13
14// nx_safety_envelope:
15// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
16// sil_target: SIL1
17// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
18// verdict: NOT_YET_EVALUATED
19
20import "syscalls.nx"
21import "runtime.nx"
22
23// strlen canonical in runtime.nx.
24
25// Compare a NUL-terminated `key` against the prefix of `entry` up to
26// the '=' separator. Returns 1 on match, 0 otherwise.
27func nx_env_key_match(entry: *u8, key: *u8) -> i64 {
28 var i: i64 = 0
29 while key[i] != 0 {
30 if entry[i] != key[i] { return 0 }
31 i = i + 1
32 }
33 if entry[i] != 0x3D { return 0 }
34 return 1
35}
36
37// Look up `key` in the NULL-terminated `envp`. Returns a pointer
38// to the value (the byte AFTER '=') or NULL if not found.
39//
40// `envp` is the standard System V envp: an array of *u8 pointers
41// terminated by NULL.
42func nx_env_get(envp: *i64, key: *u8) -> *u8 {
43 var i: i64 = 0
44 while envp[i] != 0 {
45 let entry: *u8 = (envp[i]) as *u8
46 if nx_env_key_match(entry, key) == 1 {
47 let key_len: i64 = strlen(key)
48 return (((entry as i64) + key_len + 1) as *u8)
49 }
50 i = i + 1
51 }
52 return 0 as *u8
53}
54
55// Count entries in envp.
56func nx_env_count(envp: *i64) -> i64 {
57 var i: i64 = 0
58 while envp[i] != 0 { i = i + 1 }
59 return i
60}
61
62// ---- self-test ---------------------------------------------------
63
64func main() -> i64 {
65 // Build a mock envp: ["HOME=/h", "PATH=/u/b", "NX_OPT=1", NULL]
66 let entries_raw: *u8 = sys_mmap(64)
67 let entries: *i64 = entries_raw as *i64
68
69 let e0: *u8 = sys_mmap(16)
70 e0[0] = 0x48; e0[1] = 0x4F; e0[2] = 0x4D; e0[3] = 0x45; e0[4] = 0x3D
71 e0[5] = 0x2F; e0[6] = 0x68; e0[7] = 0
72 let e1: *u8 = sys_mmap(16)
73 e1[0] = 0x50; e1[1] = 0x41; e1[2] = 0x54; e1[3] = 0x48; e1[4] = 0x3D
74 e1[5] = 0x2F; e1[6] = 0x75; e1[7] = 0x2F; e1[8] = 0x62; e1[9] = 0
75 let e2: *u8 = sys_mmap(16)
76 e2[0] = 0x4E; e2[1] = 0x58; e2[2] = 0x5F; e2[3] = 0x4F; e2[4] = 0x50; e2[5] = 0x54
77 e2[6] = 0x3D; e2[7] = 0x31; e2[8] = 0
78 entries[0] = e0 as i64
79 entries[1] = e1 as i64
80 entries[2] = e2 as i64
81 entries[3] = 0
82
83 if nx_env_count(entries) != 3 { return __syscall(93, 1, 0, 0, 0, 0, 0) }
84
85 // Lookup HOME
86 let key1: *u8 = sys_mmap(8)
87 key1[0] = 0x48; key1[1] = 0x4F; key1[2] = 0x4D; key1[3] = 0x45; key1[4] = 0
88 let v1: *u8 = nx_env_get(entries, key1)
89 if v1 == (0 as *u8) { return __syscall(93, 2, 0, 0, 0, 0, 0) }
90 if v1[0] != 0x2F { return __syscall(93, 3, 0, 0, 0, 0, 0) }
91 if v1[1] != 0x68 { return __syscall(93, 4, 0, 0, 0, 0, 0) }
92 if v1[2] != 0 { return __syscall(93, 5, 0, 0, 0, 0, 0) }
93
94 // Lookup NX_OPT
95 let key2: *u8 = sys_mmap(8)
96 key2[0] = 0x4E; key2[1] = 0x58; key2[2] = 0x5F; key2[3] = 0x4F
97 key2[4] = 0x50; key2[5] = 0x54; key2[6] = 0
98 let v2: *u8 = nx_env_get(entries, key2)
99 if v2 == (0 as *u8) { return __syscall(93, 6, 0, 0, 0, 0, 0) }
100 if v2[0] != 0x31 { return __syscall(93, 7, 0, 0, 0, 0, 0) }
101 if v2[1] != 0 { return __syscall(93, 8, 0, 0, 0, 0, 0) }
102
103 // Lookup non-existent key
104 let key3: *u8 = sys_mmap(8)
105 key3[0] = 0x42; key3[1] = 0x41; key3[2] = 0x44; key3[3] = 0
106 let v3: *u8 = nx_env_get(entries, key3)
107 if v3 != (0 as *u8) { return __syscall(93, 9, 0, 0, 0, 0, 0) }
108
109 // Key is a prefix of an entry but no '=' boundary (HOM != HOME)
110 let key4: *u8 = sys_mmap(8)
111 key4[0] = 0x48; key4[1] = 0x4F; key4[2] = 0x4D; key4[3] = 0
112 let v4: *u8 = nx_env_get(entries, key4)
113 if v4 != (0 as *u8) { return __syscall(93, 10, 0, 0, 0, 0, 0) }
114
115 return 0
116}