1#[repr(C)]
5pub struct ServEnt {
6 pub s_name: *mut c_char,
7 pub s_aliases: *mut *mut c_char,
8 pub s_port: c_int,
9 pub s_proto: *mut c_char,
10}
11
12#[repr(C)]
13pub struct ProtoEnt {
14 pub p_name: *mut c_char,
15 pub p_aliases: *mut *mut c_char,
16 pub p_proto: c_int,
17}
18
19#[repr(C)]
20pub struct NetEnt {
21 pub n_name: *mut c_char,
22 pub n_aliases: *mut *mut c_char,
23 pub n_addrtype: c_int,
24 pub n_net: u32,
25}
26
27const NDB_ENOENT: c_int = 2;
28const NDB_ERANGE: c_int = 34;
29const NDB_ENOTTY: c_int = 25;
30
31const EAI_BADFLAGS_V: c_int = -1;
32const EAI_NONAME_V: c_int = -2;
33const EAI_AGAIN_V: c_int = -3;
34const EAI_FAIL_V: c_int = -4;
35const EAI_FAMILY_V: c_int = -6;
36const EAI_SOCKTYPE_V: c_int = -7;
37const EAI_SERVICE_V: c_int = -8;
38const EAI_MEMORY_V: c_int = -10;
39const EAI_SYSTEM_V: c_int = -11;
40const EAI_OVERFLOW_V: c_int = -12;
41
42const AI_PASSIVE_V: c_int = 0x01;
43const AI_CANONNAME_V: c_int = 0x02;
44const AI_NUMERICHOST_V: c_int = 0x04;
45const AI_V4MAPPED_V: c_int = 0x08;
46const AI_ALL_V: c_int = 0x10;
47const AI_ADDRCONFIG_V: c_int = 0x20;
48const AI_NUMERICSERV_V: c_int = 0x400;
49
50const NI_NUMERICHOST_V: c_int = 0x01;
51const NI_NUMERICSERV_V: c_int = 0x02;
52const NI_NOFQDN_V: c_int = 0x04;
53const NI_NAMEREQD_V: c_int = 0x08;
54const NI_DGRAM_V: c_int = 0x10;
55const NI_NUMERICSCOPE_V: c_int = 0x100;
56
57unsafe fn nd_isspace(c: c_char) -> bool {
58 c == b' ' as c_char || c == b'\t' as c_char || c == b'\r' as c_char || c == b'\n' as c_char
59}
60
61unsafe fn nd_copy_line(src: *const c_char, dst: *mut c_char, cap: usize) -> bool {
62 let mut i = 0usize;
63 while i + 1 < cap {
64 let c = *src.add(i);
65 *dst.add(i) = c;
66 if c == 0 { return true; }
67 i += 1;
68 }
69 *dst.add(cap - 1) = 0;
70 true
71}
72
73unsafe fn nd_split(buf: *mut c_char, toks: *mut *mut c_char, maxtok: usize) -> usize {
75 let mut n = 0usize;
76 let mut p = buf;
77 loop {
78 while *p != 0 && nd_isspace(*p) { p = p.add(1); }
79 if *p == 0 || *p == b'#' as c_char { break; }
80 if n < maxtok {
81 *toks.add(n) = p;
82 n += 1;
83 }
84 while *p != 0 && !nd_isspace(*p) && *p != b'#' as c_char { p = p.add(1); }
85 if *p == 0 { break; }
86 if *p == b'#' as c_char { *p = 0; break; }
87 *p = 0;
88 p = p.add(1);
89 }
90 n
91}
92
93unsafe fn nd_tokens(line: *const c_char, buf: *mut c_char, cap: usize, toks: &mut [*mut c_char; 24]) -> usize {
94 if !nd_copy_line(line, buf, cap) { return 0; }
95 nd_split(buf, toks.as_mut_ptr(), toks.len())
96}
97
98static mut SERV_FILE: *mut FILE = core::ptr::null_mut();
103static mut SERV_ENT: ServEnt = ServEnt {
104 s_name: core::ptr::null_mut(),
105 s_aliases: core::ptr::null_mut(),
106 s_port: 0,
107 s_proto: core::ptr::null_mut(),
108};
109static mut SERV_BUF: [c_char; 1024] = [0; 1024];
110static mut SERV_ALIASES: [*mut c_char; 16] = [core::ptr::null_mut(); 16];
111
112unsafe fn serv_parse(line: *const c_char) -> bool {
113 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
114 let n = nd_tokens(line, SERV_BUF.as_mut_ptr(), SERV_BUF.len(), &mut toks);
115 if n < 2 { return false; }
116 let mut p = toks[1];
117 let port = crate::strtoul(p, &mut p, 10);
118 if p == toks[1] || port > 65535 { return false; }
119 let mut proto: *mut c_char = b"tcp\0".as_ptr() as *mut c_char;
120 if *p == b'/' as c_char {
121 p = p.add(1);
122 if *p == 0 { return false; }
123 proto = p;
124 }
125 SERV_ENT.s_name = toks[0];
126 SERV_ENT.s_port = htons(port as u16) as c_int;
127 SERV_ENT.s_proto = proto;
128 let mut ai = 0usize;
129 for i in 2..n {
130 if ai + 1 >= SERV_ALIASES.len() { break; }
131 SERV_ALIASES[ai] = toks[i];
132 ai += 1;
133 }
134 SERV_ALIASES[ai] = core::ptr::null_mut();
135 SERV_ENT.s_aliases = SERV_ALIASES.as_mut_ptr();
136 true
137}
138
139unsafe fn serv_next(f: *mut FILE) -> bool {
140 let mut line = [0 as c_char; 1024];
141 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
142 if serv_parse(line.as_ptr()) { return true; }
143 }
144 false
145}
146
147#[no_mangle]
148pub unsafe extern "C" fn setservent(stayopen: c_int) {
149 endservent();
150 SERV_FILE = crate::fopen(b"/etc/services\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
151 let _ = stayopen;
152}
153
154#[no_mangle]
155pub unsafe extern "C" fn endservent() {
156 if !SERV_FILE.is_null() {
157 crate::fclose(SERV_FILE);
158 SERV_FILE = core::ptr::null_mut();
159 }
160}
161
162#[no_mangle]
163pub unsafe extern "C" fn getservent() -> *mut ServEnt {
164 if SERV_FILE.is_null() {
165 SERV_FILE = crate::fopen(b"/etc/services\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
166 if SERV_FILE.is_null() { return core::ptr::null_mut(); }
167 }
168 if serv_next(SERV_FILE) { &raw mut SERV_ENT } else { core::ptr::null_mut() }
169}
170
171unsafe fn serv_name_matches(name: *const c_char) -> bool {
172 if crate::strcmp(SERV_ENT.s_name as *const u8, name as *const u8) == 0 { return true; }
173 let mut i = 0usize;
174 while !(*SERV_ENT.s_aliases.add(i)).is_null() {
175 if crate::strcmp(*SERV_ENT.s_aliases.add(i) as *const u8, name as *const u8) == 0 {
176 return true;
177 }
178 i += 1;
179 }
180 false
181}
182
183unsafe fn serv_proto_matches(proto: *const c_char) -> bool {
184 proto.is_null() || crate::strcmp(SERV_ENT.s_proto as *const u8, proto as *const u8) == 0
185}
186
187unsafe fn serv_search(name: *const c_char, proto: *const c_char, port: c_int) -> bool {
188 let f = crate::fopen(b"/etc/services\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
189 if f.is_null() { return false; }
190 let mut found = false;
191 while serv_next(f) {
192 if !serv_proto_matches(proto) { continue; }
193 let hit = if name.is_null() {
194 SERV_ENT.s_port == port
195 } else {
196 serv_name_matches(name)
197 };
198 if hit { found = true; break; }
199 }
200 crate::fclose(f);
201 found
202}
203
204#[no_mangle]
205pub unsafe extern "C" fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut ServEnt {
206 if name.is_null() { return core::ptr::null_mut(); }
207 if serv_search(name, proto, 0) { &raw mut SERV_ENT } else { core::ptr::null_mut() }
208}
209
210#[no_mangle]
211pub unsafe extern "C" fn getservbyport(port: c_int, proto: *const c_char) -> *mut ServEnt {
212 if serv_search(core::ptr::null(), proto, port) { &raw mut SERV_ENT } else { core::ptr::null_mut() }
213}
214
215unsafe fn serv_copy_out(se: *mut ServEnt, buf: *mut c_char, buflen: usize, res: *mut *mut ServEnt) -> c_int {
216 if res.is_null() || se.is_null() { return EINVAL; }
217 *res = core::ptr::null_mut();
218 let ptrsz = core::mem::size_of::<*mut c_char>();
219 let mut need = crate::strlen((*se).s_name) + 1 + crate::strlen((*se).s_proto) + 1;
220 let mut nalias = 0usize;
221 while !(*(*se).s_aliases.add(nalias)).is_null() {
222 need += crate::strlen(*(*se).s_aliases.add(nalias)) + 1;
223 nalias += 1;
224 }
225 let align = (ptrsz - (buf as usize & (ptrsz - 1))) & (ptrsz - 1);
226 need += align + (nalias + 1) * ptrsz;
227 if need > buflen { return NDB_ERANGE; }
228
229 let mut p = buf.add(align);
230 let aliases = p as *mut *mut c_char;
231 p = p.add((nalias + 1) * ptrsz);
232
233 let n = crate::strlen((*se).s_name);
234 core::ptr::copy_nonoverlapping((*se).s_name, p, n + 1);
235 (*se).s_name = p;
236 p = p.add(n + 1);
237
238 let n = crate::strlen((*se).s_proto);
239 core::ptr::copy_nonoverlapping((*se).s_proto, p, n + 1);
240 (*se).s_proto = p;
241 p = p.add(n + 1);
242
243 for j in 0..nalias {
244 let src = *(*se).s_aliases.add(j);
245 let n = crate::strlen(src);
246 core::ptr::copy_nonoverlapping(src, p, n + 1);
247 *aliases.add(j) = p;
248 p = p.add(n + 1);
249 }
250 *aliases.add(nalias) = core::ptr::null_mut();
251 (*se).s_aliases = aliases;
252 *res = se;
253 0
254}
255
256#[no_mangle]
257pub unsafe extern "C" fn getservbyname_r(
258 name: *const c_char,
259 proto: *const c_char,
260 _se: *mut ServEnt,
261 buf: *mut c_char,
262 buflen: usize,
263 res: *mut *mut ServEnt,
264) -> c_int {
265 if res.is_null() { return EINVAL; }
266 *res = core::ptr::null_mut();
267 let p = getservbyname(name, proto);
268 if p.is_null() { return NDB_ENOENT; }
269 let mut tmp = ServEnt { s_name: (*p).s_name, s_aliases: (*p).s_aliases, s_port: (*p).s_port, s_proto: (*p).s_proto };
270 serv_copy_out(&mut tmp, buf, buflen, res)
271}
272
273#[no_mangle]
274pub unsafe extern "C" fn getservbyport_r(
275 port: c_int,
276 proto: *const c_char,
277 _se: *mut ServEnt,
278 buf: *mut c_char,
279 buflen: usize,
280 res: *mut *mut ServEnt,
281) -> c_int {
282 if res.is_null() { return EINVAL; }
283 *res = core::ptr::null_mut();
284 let p = getservbyport(port, proto);
285 if p.is_null() { return NDB_ENOENT; }
286 let mut tmp = ServEnt { s_name: (*p).s_name, s_aliases: (*p).s_aliases, s_port: (*p).s_port, s_proto: (*p).s_proto };
287 serv_copy_out(&mut tmp, buf, buflen, res)
288}
289
290static PROTO_TABLE: [(&[u8], c_int); 36] = [
295 (b"ip\0", 0), (b"icmp\0", 1), (b"igmp\0", 2), (b"ggp\0", 3),
296 (b"ipencap\0", 4), (b"st\0", 5), (b"tcp\0", 6), (b"egp\0", 8),
297 (b"pup\0", 12), (b"udp\0", 17), (b"hmp\0", 20), (b"xns-idp\0", 22),
298 (b"rdp\0", 27), (b"iso-tp4\0", 29), (b"xtp\0", 36), (b"ddp\0", 37),
299 (b"idpr-cmtp\0", 38), (b"ipv6\0", 41), (b"ipv6-route\0", 43),
300 (b"ipv6-frag\0", 44), (b"idrp\0", 45), (b"rsvp\0", 46), (b"gre\0", 47),
301 (b"esp\0", 50), (b"ah\0", 51), (b"skip\0", 57), (b"ipv6-icmp\0", 58),
302 (b"ipv6-nonxt\0", 59), (b"ipv6-opts\0", 60), (b"rspf\0", 73),
303 (b"vmtp\0", 81), (b"ospf\0", 89), (b"ipip\0", 94), (b"encap\0", 98),
304 (b"pim\0", 103), (b"raw\0", 255),
305];
306
307static mut PROTO_FILE: *mut FILE = core::ptr::null_mut();
308static mut PROTO_ENT: ProtoEnt = ProtoEnt {
309 p_name: core::ptr::null_mut(),
310 p_aliases: core::ptr::null_mut(),
311 p_proto: 0,
312};
313static mut PROTO_BUF: [c_char; 1024] = [0; 1024];
314static mut PROTO_ALIASES: [*mut c_char; 16] = [core::ptr::null_mut(); 16];
315static mut PROTO_IDX: usize = 0;
316
317unsafe fn proto_parse(line: *const c_char) -> bool {
318 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
319 let n = nd_tokens(line, PROTO_BUF.as_mut_ptr(), PROTO_BUF.len(), &mut toks);
320 if n < 2 { return false; }
321 let num = crate::strtol(toks[1], core::ptr::null_mut(), 10);
322 if num < 0 || num > 255 { return false; }
323 PROTO_ENT.p_name = toks[0];
324 PROTO_ENT.p_proto = num as c_int;
325 let mut ai = 0usize;
326 for i in 2..n {
327 if ai + 1 >= PROTO_ALIASES.len() { break; }
328 PROTO_ALIASES[ai] = toks[i];
329 ai += 1;
330 }
331 PROTO_ALIASES[ai] = core::ptr::null_mut();
332 PROTO_ENT.p_aliases = PROTO_ALIASES.as_mut_ptr();
333 true
334}
335
336unsafe fn proto_from_table(i: usize) -> bool {
337 if i >= PROTO_TABLE.len() { return false; }
338 PROTO_ENT.p_name = PROTO_TABLE[i].0.as_ptr() as *mut c_char;
339 PROTO_ENT.p_proto = PROTO_TABLE[i].1;
340 PROTO_ALIASES[0] = core::ptr::null_mut();
341 PROTO_ENT.p_aliases = PROTO_ALIASES.as_mut_ptr();
342 true
343}
344
345unsafe fn proto_file() -> *mut FILE {
346 if PROTO_FILE.is_null() {
347 PROTO_FILE = crate::fopen(b"/etc/protocols\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
348 }
349 PROTO_FILE
350}
351
352#[no_mangle]
353pub unsafe extern "C" fn setprotoent(stayopen: c_int) {
354 endprotoent();
355 PROTO_IDX = 0;
356 PROTO_FILE = crate::fopen(b"/etc/protocols\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
357 let _ = stayopen;
358}
359
360#[no_mangle]
361pub unsafe extern "C" fn endprotoent() {
362 if !PROTO_FILE.is_null() {
363 crate::fclose(PROTO_FILE);
364 PROTO_FILE = core::ptr::null_mut();
365 }
366 PROTO_IDX = 0;
367}
368
369#[no_mangle]
370pub unsafe extern "C" fn getprotoent() -> *mut ProtoEnt {
371 if PROTO_FILE.is_null() {
372 let f = crate::fopen(b"/etc/protocols\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
373 if f.is_null() {
374 let ok = proto_from_table(PROTO_IDX);
375 PROTO_IDX += 1;
376 return if ok { &raw mut PROTO_ENT } else { core::ptr::null_mut() };
377 }
378 PROTO_FILE = f;
379 }
380 let mut line = [0 as c_char; 1024];
381 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, PROTO_FILE).is_null() {
382 if proto_parse(line.as_ptr()) { return &raw mut PROTO_ENT; }
383 }
384 core::ptr::null_mut()
385}
386
387unsafe fn proto_name_matches(name: *const c_char) -> bool {
388 if crate::strcmp(PROTO_ENT.p_name as *const u8, name as *const u8) == 0 { return true; }
389 let mut i = 0usize;
390 while !(*PROTO_ENT.p_aliases.add(i)).is_null() {
391 if crate::strcmp(*PROTO_ENT.p_aliases.add(i) as *const u8, name as *const u8) == 0 { return true; }
392 i += 1;
393 }
394 false
395}
396
397unsafe fn proto_scan(name: *const c_char, num: c_int, by_name: bool) -> bool {
398 let f = crate::fopen(b"/etc/protocols\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
399 if !f.is_null() {
400 let mut line = [0 as c_char; 1024];
401 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
402 if !proto_parse(line.as_ptr()) { continue; }
403 let hit = if by_name { proto_name_matches(name) } else { PROTO_ENT.p_proto == num };
404 if hit { crate::fclose(f); return true; }
405 }
406 crate::fclose(f);
407 }
408 for i in 0..PROTO_TABLE.len() {
409 proto_from_table(i);
410 let hit = if by_name { proto_name_matches(name) } else { PROTO_ENT.p_proto == num };
411 if hit { return true; }
412 }
413 false
414}
415
416#[no_mangle]
417pub unsafe extern "C" fn getprotobyname(name: *const c_char) -> *mut ProtoEnt {
418 if name.is_null() { return core::ptr::null_mut(); }
419 if proto_scan(name, 0, true) { &raw mut PROTO_ENT } else { core::ptr::null_mut() }
420}
421
422#[no_mangle]
423pub unsafe extern "C" fn getprotobynumber(num: c_int) -> *mut ProtoEnt {
424 if proto_scan(core::ptr::null(), num, false) { &raw mut PROTO_ENT } else { core::ptr::null_mut() }
425}
426
427static mut NET_FILE: *mut FILE = core::ptr::null_mut();
432static mut NET_ENT: NetEnt = NetEnt {
433 n_name: core::ptr::null_mut(),
434 n_aliases: core::ptr::null_mut(),
435 n_addrtype: AF_INET,
436 n_net: 0,
437};
438static mut NET_BUF: [c_char; 1024] = [0; 1024];
439static mut NET_ALIASES: [*mut c_char; 16] = [core::ptr::null_mut(); 16];
440
441unsafe fn net_parse(line: *const c_char) -> bool {
442 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
443 let n = nd_tokens(line, NET_BUF.as_mut_ptr(), NET_BUF.len(), &mut toks);
444 if n < 2 { return false; }
445 let net = inet_network(toks[1]);
446 if net == u32::MAX { return false; }
447 NET_ENT.n_name = toks[0];
448 NET_ENT.n_addrtype = AF_INET;
449 NET_ENT.n_net = net;
450 let mut ai = 0usize;
451 for i in 2..n {
452 if ai + 1 >= NET_ALIASES.len() { break; }
453 NET_ALIASES[ai] = toks[i];
454 ai += 1;
455 }
456 NET_ALIASES[ai] = core::ptr::null_mut();
457 NET_ENT.n_aliases = NET_ALIASES.as_mut_ptr();
458 true
459}
460
461unsafe fn net_next(f: *mut FILE) -> bool {
462 let mut line = [0 as c_char; 1024];
463 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
464 if net_parse(line.as_ptr()) { return true; }
465 }
466 false
467}
468
469#[no_mangle]
470pub unsafe extern "C" fn setnetent(stayopen: c_int) {
471 endnetent();
472 NET_FILE = crate::fopen(b"/etc/networks\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
473 let _ = stayopen;
474}
475
476#[no_mangle]
477pub unsafe extern "C" fn endnetent() {
478 if !NET_FILE.is_null() {
479 crate::fclose(NET_FILE);
480 NET_FILE = core::ptr::null_mut();
481 }
482}
483
484#[no_mangle]
485pub unsafe extern "C" fn getnetent() -> *mut NetEnt {
486 if NET_FILE.is_null() {
487 NET_FILE = crate::fopen(b"/etc/networks\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
488 if NET_FILE.is_null() { return core::ptr::null_mut(); }
489 }
490 if net_next(NET_FILE) { &raw mut NET_ENT } else { core::ptr::null_mut() }
491}
492
493unsafe fn net_name_matches(name: *const c_char) -> bool {
494 if crate::strcmp(NET_ENT.n_name as *const u8, name as *const u8) == 0 { return true; }
495 let mut i = 0usize;
496 while !(*NET_ENT.n_aliases.add(i)).is_null() {
497 if crate::strcmp(*NET_ENT.n_aliases.add(i) as *const u8, name as *const u8) == 0 { return true; }
498 i += 1;
499 }
500 false
501}
502
503#[no_mangle]
504pub unsafe extern "C" fn getnetbyname(name: *const c_char) -> *mut NetEnt {
505 if name.is_null() { return core::ptr::null_mut(); }
506 let f = crate::fopen(b"/etc/networks\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
507 if !f.is_null() {
508 while net_next(f) {
509 if net_name_matches(name) { crate::fclose(f); return &raw mut NET_ENT; }
510 }
511 crate::fclose(f);
512 }
513 if crate::strcmp(name as *const u8, b"loopback\0".as_ptr()) == 0 {
515 net_parse(b"loopback 127.0.0.0\0".as_ptr() as *const c_char);
516 return &raw mut NET_ENT;
517 }
518 if crate::strcmp(name as *const u8, b"default\0".as_ptr()) == 0 {
519 net_parse(b"default 0.0.0.0\0".as_ptr() as *const c_char);
520 return &raw mut NET_ENT;
521 }
522 core::ptr::null_mut()
523}
524
525#[no_mangle]
526pub unsafe extern "C" fn getnetbyaddr(net: u32, type_: c_int) -> *mut NetEnt {
527 if type_ != AF_INET { return core::ptr::null_mut(); }
528 let f = crate::fopen(b"/etc/networks\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
529 if !f.is_null() {
530 while net_next(f) {
531 let shift = if NET_ENT.n_net < 0x80000000 { 24 }
532 else if NET_ENT.n_net < 0xc0000000 { 16 } else { 8 };
533 if (NET_ENT.n_net >> shift) == (net >> shift) { crate::fclose(f); return &raw mut NET_ENT; }
534 }
535 crate::fclose(f);
536 }
537 core::ptr::null_mut()
538}
539
540#[no_mangle]
545pub unsafe extern "C" fn ether_line(line: *const c_char, ea: *mut u8, hostname: *mut c_char) -> c_int {
546 if line.is_null() || ea.is_null() || hostname.is_null() { return -1; }
547 let mut buf = [0 as c_char; 512];
548 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
549 let n = nd_tokens(line, buf.as_mut_ptr(), buf.len(), &mut toks);
550 if n < 2 { return -1; }
551 if ether_aton_r(toks[0], ea).is_null() { return -1; }
552 let mut i = 0usize;
553 while *toks[1].add(i) != 0 {
554 *hostname.add(i) = *toks[1].add(i);
555 i += 1;
556 }
557 *hostname.add(i) = 0;
558 0
559}
560
561unsafe fn ether_scan(want_name: *const c_char, ea: *mut u8, hostname: *mut c_char) -> c_int {
562 let f = crate::fopen(b"/etc/ethers\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
563 if f.is_null() { return -1; }
564 let mut line = [0 as c_char; 512];
565 let mut found = -1;
566 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
567 let mut mac = [0u8; 6];
568 let mut host = [0 as c_char; 256];
569 if ether_line(line.as_ptr(), mac.as_mut_ptr(), host.as_mut_ptr()) != 0 { continue; }
570 if !want_name.is_null() {
571 if crate::strcmp(host.as_ptr() as *const u8, want_name as *const u8) != 0 { continue; }
572 core::ptr::copy_nonoverlapping(mac.as_ptr(), ea, 6);
573 found = 0;
574 break;
575 } else {
576 let mut same = true;
577 for i in 0..6 {
578 if mac[i] != *ea.add(i) { same = false; break; }
579 }
580 if !same { continue; }
581 let mut i = 0usize;
582 while host[i] != 0 {
583 *hostname.add(i) = host[i];
584 i += 1;
585 }
586 *hostname.add(i) = 0;
587 found = 0;
588 break;
589 }
590 }
591 crate::fclose(f);
592 found
593}
594
595#[no_mangle]
596pub unsafe extern "C" fn ether_hostton(hostname: *const c_char, ea: *mut u8) -> c_int {
597 if hostname.is_null() || ea.is_null() { return -1; }
598 ether_scan(hostname, ea, core::ptr::null_mut())
599}
600
601#[no_mangle]
602pub unsafe extern "C" fn ether_ntohost(hostname: *mut c_char, ea: *const u8) -> c_int {
603 if hostname.is_null() || ea.is_null() { return -1; }
604 ether_scan(core::ptr::null(), ea as *mut u8, hostname)
605}
606
607static mut HOSTS_FILE: *mut FILE = core::ptr::null_mut();
612static mut HOSTS_BUF: [c_char; 1024] = [0; 1024];
613static mut HOSTS_ADDR: [u8; 4] = [0; 4];
614static mut HOSTS_ADDR_PTRS: [*mut c_char; 2] = [core::ptr::null_mut(); 2];
615static mut HOSTS_ALIASES: [*mut c_char; 16] = [core::ptr::null_mut(); 16];
616
617unsafe fn hosts_parse(line: *const c_char) -> bool {
618 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
619 let n = nd_tokens(line, HOSTS_BUF.as_mut_ptr(), HOSTS_BUF.len(), &mut toks);
620 if n < 2 { return false; }
621 if inet_pton(AF_INET, toks[0], HOSTS_ADDR.as_mut_ptr() as *mut c_void) != 1 { return false; }
622 HOST_ENT.h_name = toks[1];
623 HOST_ENT.h_addrtype = AF_INET;
624 HOST_ENT.h_length = 4;
625 HOST_ENT.h_addr_list = HOSTS_ADDR_PTRS.as_mut_ptr();
626 HOSTS_ADDR_PTRS[0] = HOSTS_ADDR.as_mut_ptr() as *mut c_char;
627 HOSTS_ADDR_PTRS[1] = core::ptr::null_mut();
628 let mut ai = 0usize;
629 for i in 2..n {
630 if ai + 1 >= HOSTS_ALIASES.len() { break; }
631 HOSTS_ALIASES[ai] = toks[i];
632 ai += 1;
633 }
634 HOSTS_ALIASES[ai] = core::ptr::null_mut();
635 HOST_ENT.h_aliases = HOSTS_ALIASES.as_mut_ptr();
636 true
637}
638
639#[no_mangle]
640pub unsafe extern "C" fn sethostent(_stayopen: c_int) {
641 endhostent();
642}
643
644#[no_mangle]
645pub unsafe extern "C" fn endhostent() {
646 if !HOSTS_FILE.is_null() {
647 crate::fclose(HOSTS_FILE);
648 HOSTS_FILE = core::ptr::null_mut();
649 }
650}
651
652#[no_mangle]
653pub unsafe extern "C" fn gethostent() -> *mut HostEnt {
654 if HOSTS_FILE.is_null() {
655 HOSTS_FILE = crate::fopen(b"/etc/hosts\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
656 if HOSTS_FILE.is_null() { return core::ptr::null_mut(); }
657 }
658 let mut line = [0 as c_char; 1024];
659 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, HOSTS_FILE).is_null() {
660 if hosts_parse(line.as_ptr()) { return &raw mut HOST_ENT; }
661 }
662 core::ptr::null_mut()
663}
664
665unsafe fn hosts_lookup_addr(addr: *const u8, family: c_int) -> bool {
666 let f = crate::fopen(b"/etc/hosts\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
667 if f.is_null() { return false; }
668 let mut line = [0 as c_char; 1024];
669 let mut found = false;
670 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
671 let mut toks: [*mut c_char; 24] = [core::ptr::null_mut(); 24];
672 let n = nd_tokens(line.as_ptr(), HOSTS_BUF.as_mut_ptr(), HOSTS_BUF.len(), &mut toks);
673 if n < 2 { continue; }
674 let mut tmp = [0u8; 16];
675 if inet_pton(AF_INET, toks[0], tmp.as_mut_ptr() as *mut c_void) == 1 {
676 if family != AF_INET { continue; }
677 } else if inet_pton(AF_INET6, toks[0], tmp.as_mut_ptr() as *mut c_void) == 1 {
678 if family != AF_INET6 { continue; }
679 } else {
680 continue;
681 }
682 let len = if family == AF_INET6 { 16 } else { 4 };
683 let mut same = true;
684 for i in 0..len {
685 if tmp[i] != *addr.add(i) { same = false; break; }
686 }
687 if !same { continue; }
688 let nl = crate::strlen(toks[1]);
689 core::ptr::copy_nonoverlapping(toks[1], HOST_NAME.as_mut_ptr(), nl + 1);
690 found = true;
691 break;
692 }
693 crate::fclose(f);
694 found
695}
696
697unsafe fn hosts_lookup_name(name: *const c_char) -> bool {
698 let f = crate::fopen(b"/etc/hosts\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
699 if f.is_null() { return false; }
700 let mut line = [0 as c_char; 1024];
701 let mut found = false;
702 while !crate::fgets(line.as_mut_ptr(), line.len() as c_int, f).is_null() {
703 if !hosts_parse(line.as_ptr()) { continue; }
704 let mut hit = crate::strcmp(HOST_ENT.h_name as *const u8, name as *const u8) == 0;
705 if !hit {
706 let mut i = 0usize;
707 while !(*HOST_ENT.h_aliases.add(i)).is_null() {
708 if crate::strcmp(*HOST_ENT.h_aliases.add(i) as *const u8, name as *const u8) == 0 {
709 hit = true;
710 break;
711 }
712 i += 1;
713 }
714 }
715 if hit { found = true; break; }
716 }
717 crate::fclose(f);
718 found
719}
720
721unsafe fn nd_itoa(mut v: u32, out: *mut c_char) -> usize {
726 let mut digits = [0u8; 10];
727 let mut n = 0usize;
728 if v == 0 { digits[0] = 0; n = 1; }
729 while v > 0 { digits[n] = (v % 10) as u8; v /= 10; n += 1; }
730 let mut o = 0usize;
731 while n > 0 { n -= 1; *out.add(o) = (b'0' + digits[n]) as c_char; o += 1; }
732 *out.add(o) = 0;
733 o
734}
735
736unsafe fn nd_reverse6(addr: *const u8, out: *mut c_char, cap: usize) -> bool {
737 if cap < 74 { return false; }
738 let hex = b"0123456789abcdef";
739 let mut o = 0usize;
740 let mut i = 16isize;
741 while i > 0 {
742 i -= 1;
743 let b = *addr.add(i as usize);
744 *out.add(o) = hex[(b & 0xf) as usize] as c_char; o += 1;
745 *out.add(o) = b'.' as c_char; o += 1;
746 *out.add(o) = hex[(b >> 4) as usize] as c_char; o += 1;
747 *out.add(o) = b'.' as c_char; o += 1;
748 }
749 for &c in b"ip6.arpa\0" { *out.add(o) = c as c_char; o += 1; }
750 true
751}
752
753#[no_mangle]
754pub unsafe extern "C" fn getnameinfo(
755 sa: *const c_void,
756 salen: u32,
757 host: *mut c_char,
758 hostlen: u32,
759 serv: *mut c_char,
760 servlen: u32,
761 flags: c_int,
762) -> c_int {
763 if sa.is_null() { return EAI_FAIL_V; }
764 let family = *(sa as *const u16) as c_int;
765 let mut addr = [0u8; 16];
766 let mut scope: u32 = 0;
767 let port: u16;
768 match family {
769 AF_INET => {
770 if salen < 16 { return EAI_FAMILY_V; }
771 port = u16::from_be(*((sa as *const u8).add(2) as *const u16));
772 core::ptr::copy_nonoverlapping((sa as *const u8).add(4), addr.as_mut_ptr(), 4);
773 }
774 AF_INET6 => {
775 if salen < 28 { return EAI_FAMILY_V; }
776 port = u16::from_be(*((sa as *const u8).add(2) as *const u16));
777 core::ptr::copy_nonoverlapping((sa as *const u8).add(8), addr.as_mut_ptr(), 16);
778 scope = *((sa as *const u8).add(24) as *const u32);
779 }
780 _ => return EAI_FAMILY_V,
781 }
782
783 if !host.is_null() && hostlen > 0 {
784 let mut buf = [0 as c_char; 300];
785 let mut have = false;
786 if flags & NI_NUMERICHOST_V == 0 {
787 have = hosts_lookup_addr(addr.as_ptr(), family);
788 if have {
789 let l = crate::strlen(HOST_NAME.as_ptr());
790 let l = core::cmp::min(l, buf.len() - 1);
791 core::ptr::copy_nonoverlapping(HOST_NAME.as_ptr(), buf.as_mut_ptr(), l);
792 buf[l] = 0;
793 }
794 if !have {
795 let mut ptr = [0 as c_char; 80];
796 let ok = if family == AF_INET {
797 let a = addr;
798 let mut o = 0usize;
800 let mut i = 4usize;
801 while i > 0 {
802 i -= 1;
803 o += nd_itoa(a[i] as u32, ptr.as_mut_ptr().add(o));
804 *ptr.as_mut_ptr().add(o) = b'.' as c_char;
805 o += 1;
806 }
807 for &c in b"in-addr.arpa\0" { *ptr.as_mut_ptr().add(o) = c as c_char; o += 1; }
808 true
809 } else {
810 nd_reverse6(addr.as_ptr(), ptr.as_mut_ptr(), ptr.len())
811 };
812 if ok {
813 let mut answer = [0u8; 512];
814 let r = res_query(ptr.as_ptr() as *const c_char, 1, 12, answer.as_mut_ptr(), answer.len() as c_int);
815 if r >= 12 {
816 let end = answer.as_ptr().add(r as usize);
817 let qd = dns_read_u16(answer.as_ptr().add(4)) as usize;
818 let an = dns_read_u16(answer.as_ptr().add(6)) as usize;
819 let mut p = answer.as_ptr().add(12);
820 for _ in 0..qd { p = dns_skip_name(p, end); p = p.add(4); }
821 for _ in 0..an {
822 p = dns_skip_name(p, end);
823 if p.add(10) > end { break; }
824 let typ = dns_read_u16(p);
825 let rdlen = dns_read_u16(p.add(8)) as usize;
826 let rdata = p.add(10);
827 if typ == 12 && dns_expand_name(rdata, answer.as_ptr(), buf.as_mut_ptr(), buf.len()) {
828 let mut l = crate::strlen(buf.as_ptr());
829 if l > 0 && buf[l - 1] == b'.' as c_char { l -= 1; }
830 buf[l] = 0;
831 have = l > 0;
832 break;
833 }
834 p = rdata.add(rdlen);
835 }
836 }
837 }
838 }
839 }
840 if !have {
841 if flags & NI_NAMEREQD_V != 0 { return EAI_NONAME_V; }
842 let aptr = if family == AF_INET { addr.as_ptr() as *const c_void } else { addr.as_ptr() as *const c_void };
843 if inet_ntop(family, aptr, buf.as_mut_ptr(), buf.len() as u32).is_null() {
844 return EAI_FAIL_V;
845 }
846 if scope != 0 && family == AF_INET6 {
847 let mut l = crate::strlen(buf.as_ptr());
848 *buf.as_mut_ptr().add(l) = b'%' as c_char;
849 l += 1;
850 let mut name = [0 as c_char; 32];
851 let have_name = flags & NI_NUMERICSCOPE_V == 0
852 && if_indextoname(scope, name.as_mut_ptr()) != core::ptr::null_mut();
853 if have_name {
854 let nl = crate::strlen(name.as_ptr());
855 core::ptr::copy_nonoverlapping(name.as_ptr(), buf.as_mut_ptr().add(l), nl + 1);
856 } else {
857 nd_itoa(scope, buf.as_mut_ptr().add(l));
858 }
859 }
860 }
861 if flags & NI_NOFQDN_V != 0 {
862 let mut i = 0usize;
863 while buf[i] != 0 {
864 if buf[i] == b'.' as c_char { buf[i] = 0; break; }
865 i += 1;
866 }
867 }
868 if crate::strlen(buf.as_ptr()) >= hostlen as usize { return EAI_OVERFLOW_V; }
869 let l = crate::strlen(buf.as_ptr());
870 core::ptr::copy_nonoverlapping(buf.as_ptr(), host, l + 1);
871 }
872
873 if !serv.is_null() && servlen > 0 {
874 let mut buf = [0 as c_char; 64];
875 let mut have = false;
876 if flags & NI_NUMERICSERV_V == 0 {
877 let proto = if flags & NI_DGRAM_V != 0 { b"udp\0" } else { b"tcp\0" };
878 let port_net = (port as u16).to_be() as c_int;
879 let se = getservbyport(port_net, proto.as_ptr() as *const c_char);
880 if !se.is_null() {
881 let l = crate::strlen((*se).s_name);
882 if l < buf.len() {
883 core::ptr::copy_nonoverlapping((*se).s_name, buf.as_mut_ptr(), l + 1);
884 have = true;
885 }
886 }
887 }
888 if !have {
889 nd_itoa(port as u32, buf.as_mut_ptr());
890 }
891 if crate::strlen(buf.as_ptr()) >= servlen as usize { return EAI_OVERFLOW_V; }
892 let l = crate::strlen(buf.as_ptr());
893 core::ptr::copy_nonoverlapping(buf.as_ptr(), serv, l + 1);
894 }
895 0
896}
897
898unsafe fn nd_make_addrinfo(
903 family: c_int,
904 socktype: c_int,
905 protocol: c_int,
906 addr: *const u8,
907 port: u16,
908 flags: c_int,
909 canon: *const c_char,
910) -> *mut AddrInfo {
911 let addrlen: usize = if family == AF_INET6 { 28 } else { 16 };
912 let canonlen = if !canon.is_null() { crate::strlen(canon) + 1 } else { 0 };
913 let total = core::mem::size_of::<AddrInfo>() + addrlen + canonlen;
914 let p = crate::malloc(total) as *mut u8;
915 if p.is_null() { return core::ptr::null_mut(); }
916 core::ptr::write_bytes(p, 0, total);
917 let ai = p as *mut AddrInfo;
918 (*ai).ai_flags = flags;
919 (*ai).ai_family = family;
920 (*ai).ai_socktype = socktype;
921 (*ai).ai_protocol = protocol;
922 (*ai).ai_addrlen = addrlen as u32;
923 let sa = p.add(core::mem::size_of::<AddrInfo>());
924 (*ai).ai_addr = sa as *mut c_void;
925 if family == AF_INET6 {
926 *(sa as *mut u16) = AF_INET6 as u16;
927 *(sa.add(2) as *mut u16) = port.to_be();
928 core::ptr::copy_nonoverlapping(addr, sa.add(8), 16);
929 } else {
930 *(sa as *mut u16) = AF_INET as u16;
931 *(sa.add(2) as *mut u16) = port.to_be();
932 core::ptr::copy_nonoverlapping(addr, sa.add(4), 4);
933 }
934 if canonlen > 0 {
935 let c = sa.add(addrlen);
936 core::ptr::copy_nonoverlapping(canon as *const u8, c, canonlen);
937 (*ai).ai_canonname = c as *mut c_char;
938 }
939 ai
940}
941
942unsafe fn nd_parse_service(service: *const c_char, socktype: c_int, protocol: c_int, port: *mut u16, proto_out: *mut c_int) -> bool {
943 if service.is_null() { *port = 0; return true; }
944 let mut end: *mut c_char = core::ptr::null_mut();
945 let v = crate::strtoul(service, &mut end, 10);
946 let numeric = !end.is_null() && *end == 0;
947 if numeric {
948 if v > 65535 { return false; }
949 *port = v as u16;
950 return true;
951 }
952 let proto_name: *const c_char = if protocol == 6 { b"tcp\0".as_ptr() as *const c_char }
953 else if protocol == 17 { b"udp\0".as_ptr() as *const c_char }
954 else if socktype == SOCK_STREAM { b"tcp\0".as_ptr() as *const c_char }
955 else if socktype == SOCK_DGRAM { b"udp\0".as_ptr() as *const c_char }
956 else { core::ptr::null() };
957 let se = getservbyname(service, proto_name);
958 if se.is_null() { return false; }
959 *port = ntohs((*se).s_port as u16);
960 *proto_out = if crate::strcmp((*se).s_proto as *const u8, b"udp\0".as_ptr()) == 0 { 17 } else { 6 };
961 true
962}
963
964#[no_mangle]
965pub unsafe extern "C" fn getaddrinfo(
966 node: *const c_char,
967 service: *const c_char,
968 hints: *const AddrInfo,
969 res: *mut *mut AddrInfo,
970) -> c_int {
971 if res.is_null() { return EAI_FAIL_V; }
972 *res = core::ptr::null_mut();
973
974 let mut family = 0;
975 let mut socktype = 0;
976 let mut protocol = 0;
977 let mut flags = 0;
978 if !hints.is_null() {
979 family = (*hints).ai_family;
980 socktype = (*hints).ai_socktype;
981 protocol = (*hints).ai_protocol;
982 flags = (*hints).ai_flags;
983 }
984 if family != 0 && family != AF_INET && family != AF_INET6 { return EAI_FAMILY_V; }
985 if socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM { return EAI_SOCKTYPE_V; }
986 if flags & AI_NUMERICSERV_V != 0 && !service.is_null() {
987 let mut end: *mut c_char = core::ptr::null_mut();
988 let _ = crate::strtoul(service, &mut end, 10);
989 if end.is_null() || *end != 0 { return EAI_NONAME_V; }
990 }
991
992 let mut port: u16 = 0;
993 let mut proto_from_service = 0;
994 if !nd_parse_service(service, socktype, protocol, &mut port, &mut proto_from_service) {
995 return EAI_SERVICE_V;
996 }
997
998 let mut addrs: [[u8; 16]; 8] = [[0; 16]; 8];
999 let mut fams: [c_int; 8] = [0; 8];
1000 let mut count = 0usize;
1001 let mut canon: [c_char; 256] = [0; 256];
1002
1003 if node.is_null() {
1004 if family == 0 || family == AF_INET6 {
1005 if family == 0 && flags & AI_V4MAPPED_V != 0 && flags & AI_ALL_V != 0 {
1006 }
1008 addrs[count] = [0; 16];
1009 if flags & AI_PASSIVE_V == 0 {
1010 addrs[count][15] = 1;
1011 }
1012 fams[count] = AF_INET6;
1013 count += 1;
1014 }
1015 if family == 0 || family == AF_INET {
1016 addrs[count] = [0; 16];
1017 if flags & AI_PASSIVE_V == 0 {
1018 addrs[count][0] = 127;
1019 addrs[count][3] = 1;
1020 }
1021 fams[count] = AF_INET;
1022 count += 1;
1023 }
1024 } else {
1025 let mut numeric = false;
1026 let mut tmp = [0u8; 16];
1027 if inet_pton(AF_INET, node, tmp.as_mut_ptr() as *mut c_void) == 1 {
1028 numeric = true;
1029 if family == 0 || family == AF_INET {
1030 addrs[count][..4].copy_from_slice(&tmp[..4]);
1031 fams[count] = AF_INET;
1032 count += 1;
1033 }
1034 }
1035 if !numeric && inet_pton(AF_INET6, node, tmp.as_mut_ptr() as *mut c_void) == 1 {
1036 numeric = true;
1037 if family == 0 || family == AF_INET6 {
1038 addrs[count] = tmp;
1039 fams[count] = AF_INET6;
1040 count += 1;
1041 }
1042 }
1043 if flags & AI_NUMERICHOST_V != 0 && !numeric {
1044 return EAI_NONAME_V;
1045 }
1046 if !numeric {
1047 let mut got = false;
1048 if hosts_lookup_name(node) {
1050 let l = core::cmp::min(crate::strlen(HOST_ENT.h_name), canon.len() - 1);
1051 core::ptr::copy_nonoverlapping(HOST_ENT.h_name, canon.as_mut_ptr(), l);
1052 canon[l] = 0;
1053 if family == 0 || family == AF_INET {
1054 core::ptr::copy_nonoverlapping(HOSTS_ADDR.as_ptr(), addrs[count].as_mut_ptr(), 4);
1055 fams[count] = AF_INET;
1056 count += 1;
1057 got = true;
1058 }
1059 if family == AF_INET6 {
1062 got = false;
1063 }
1064 }
1065 if !got {
1066 let order: [c_int; 2] = if family == AF_INET6 { [AF_INET6, AF_INET] } else { [AF_INET, AF_INET6] };
1067 for &f in &order {
1068 if family != 0 && family != f { continue; }
1069 let h = gethostbyname2(node, f);
1070 if h.is_null() { continue; }
1071 let n = core::cmp::min((*h).h_length as usize, 16);
1072 core::ptr::copy_nonoverlapping((*h).h_addr_list.read() as *const u8, addrs[count].as_mut_ptr(), n);
1073 fams[count] = f;
1074 count += 1;
1075 let hl = crate::strlen((*h).h_name);
1076 let l = core::cmp::min(hl, canon.len() - 1);
1077 core::ptr::copy_nonoverlapping((*h).h_name, canon.as_mut_ptr(), l);
1078 canon[l] = 0;
1079 got = true;
1080 if family != 0 { break; }
1081 }
1082 }
1083 if !got {
1084 return if h_errno == TRY_AGAIN { EAI_AGAIN_V } else { EAI_NONAME_V };
1085 }
1086 }
1087 }
1088 if count == 0 { return EAI_NONAME_V; }
1089
1090 let canonptr: *const c_char = if flags & AI_CANONNAME_V != 0 && canon[0] != 0 {
1091 canon.as_ptr()
1092 } else if flags & AI_CANONNAME_V != 0 && !node.is_null() {
1093 node
1094 } else {
1095 core::ptr::null()
1096 };
1097
1098 let mut head: *mut AddrInfo = core::ptr::null_mut();
1099 let mut tail: *mut AddrInfo = core::ptr::null_mut();
1100 let mut emitted = 0usize;
1101 for i in 0..count {
1102 let types: [c_int; 2] = if socktype == 0 { [SOCK_STREAM, SOCK_DGRAM] } else { [socktype, socktype] };
1103 let ntypes = if socktype == 0 { 2 } else { 1 };
1104 for t in 0..ntypes {
1105 let st = types[t];
1106 if protocol != 0 {
1107 if (protocol == 6 && st != SOCK_STREAM) || (protocol == 17 && st != SOCK_DGRAM) { continue; }
1108 }
1109 if proto_from_service != 0 && protocol == 0 {
1110 if (proto_from_service == 6 && st != SOCK_STREAM) || (proto_from_service == 17 && st != SOCK_DGRAM) { continue; }
1111 }
1112 let proto = if protocol != 0 { protocol } else if st == SOCK_STREAM { 6 } else { 17 };
1113 let cp = if emitted == 0 { canonptr } else { core::ptr::null() };
1114 let ai = nd_make_addrinfo(fams[i], st, proto, addrs[i].as_ptr(), port, flags, cp);
1115 if ai.is_null() {
1116 freeaddrinfo(head);
1117 return EAI_MEMORY_V;
1118 }
1119 if head.is_null() { head = ai; } else { (*tail).ai_next = ai; }
1120 tail = ai;
1121 emitted += 1;
1122 }
1123 }
1124 if emitted == 0 { return EAI_SERVICE_V; }
1125 *res = head;
1126 0
1127}
1128
1129#[no_mangle]
1130pub unsafe extern "C" fn freeaddrinfo(mut ai: *mut AddrInfo) {
1131 while !ai.is_null() {
1132 let next = (*ai).ai_next;
1133 crate::free(ai as *mut c_void);
1134 ai = next;
1135 }
1136}
1137
1138#[no_mangle]
1139pub unsafe extern "C" fn gai_strerror(code: c_int) -> *const c_char {
1140 let s: &[u8] = match code {
1141 EAI_BADFLAGS_V => b"Bad flags\0",
1142 EAI_NONAME_V => b"Name not known\0",
1143 EAI_AGAIN_V => b"Try again\0",
1144 EAI_FAIL_V => b"Non-recoverable failure\0",
1145 -5 => b"No address data\0",
1146 EAI_FAMILY_V => b"Unsupported family\0",
1147 EAI_SOCKTYPE_V => b"Unsupported socket type\0",
1148 EAI_SERVICE_V => b"Unsupported service\0",
1149 -9 => b"Address family not supported\0",
1150 EAI_MEMORY_V => b"Out of memory\0",
1151 EAI_SYSTEM_V => b"System error\0",
1152 EAI_OVERFLOW_V => b"Overflow\0",
1153 _ => b"Unknown error\0",
1154 };
1155 s.as_ptr() as *const c_char
1156}
1157
1158#[no_mangle]
1163pub unsafe extern "C" fn ttyname_r(fd: c_int, name: *mut c_char, size: usize) -> c_int {
1164 if name.is_null() || size == 0 { return EINVAL; }
1165 if crate::isatty(fd) != 1 { return NDB_ENOTTY; }
1166 let mut procname = [0 as c_char; 32];
1167 let mut o = 0usize;
1168 for &c in b"/proc/self/fd/" { procname[o] = c as c_char; o += 1; }
1169 o += nd_itoa(fd as u32, procname.as_mut_ptr().add(o));
1170 procname[o] = 0;
1171 let n = crate::readlink(procname.as_ptr(), name, size - 1);
1172 if n < 0 { return ERRNO; }
1173 if n as usize == size - 1 { return NDB_ERANGE; }
1174 *name.add(n as usize) = 0;
1175 0
1176}
1177
1178#[no_mangle]
1179pub unsafe extern "C" fn ttyname(fd: c_int) -> *mut c_char {
1180 static mut TTY_BUF: [c_char; 64] = [0; 64];
1181 if ttyname_r(fd, TTY_BUF.as_mut_ptr(), TTY_BUF.len()) != 0 {
1182 core::ptr::null_mut()
1183 } else {
1184 TTY_BUF.as_mut_ptr()
1185 }
1186}
1187
1188unsafe fn host_copy_out(
1193 h: *mut HostEnt,
1194 ret: *mut HostEnt,
1195 buf: *mut c_char,
1196 buflen: usize,
1197 result: *mut *mut HostEnt,
1198) -> c_int {
1199 if result.is_null() { return EINVAL; }
1200 *result = core::ptr::null_mut();
1201 let ptrsz = core::mem::size_of::<*mut c_char>();
1202 let mut need = crate::strlen((*h).h_name) + 1;
1203 let mut nalias = 0usize;
1204 if !(*h).h_aliases.is_null() {
1205 while !(*(*h).h_aliases.add(nalias)).is_null() {
1206 need += crate::strlen(*(*h).h_aliases.add(nalias)) + 1;
1207 nalias += 1;
1208 }
1209 }
1210 let alen = (*h).h_length as usize;
1211 let align = (ptrsz - (buf as usize & (ptrsz - 1))) & (ptrsz - 1);
1212 need += align + (nalias + 1) * ptrsz + alen + 2 * ptrsz;
1213 if need > buflen { return NDB_ERANGE; }
1214
1215 let mut p = buf.add(align);
1216 let aliases = p as *mut *mut c_char;
1217 p = p.add((nalias + 1) * ptrsz);
1218 let addr_list = p as *mut *mut c_char;
1219 p = p.add(2 * ptrsz);
1220
1221 let n = crate::strlen((*h).h_name);
1222 core::ptr::copy_nonoverlapping((*h).h_name, p, n + 1);
1223 (*ret).h_name = p;
1224 p = p.add(n + 1);
1225
1226 for i in 0..nalias {
1227 let src = *(*h).h_aliases.add(i);
1228 let n = crate::strlen(src);
1229 core::ptr::copy_nonoverlapping(src, p, n + 1);
1230 *aliases.add(i) = p;
1231 p = p.add(n + 1);
1232 }
1233 *aliases.add(nalias) = core::ptr::null_mut();
1234
1235 let src = *(*h).h_addr_list;
1236 core::ptr::copy_nonoverlapping(src, p, alen);
1237 *addr_list = p;
1238 *addr_list.add(1) = core::ptr::null_mut();
1239
1240 (*ret).h_aliases = aliases;
1241 (*ret).h_addrtype = (*h).h_addrtype;
1242 (*ret).h_length = (*h).h_length;
1243 (*ret).h_addr_list = addr_list;
1244 *result = ret;
1245 0
1246}
1247
1248#[no_mangle]
1249pub unsafe extern "C" fn gethostbyname_r(
1250 name: *const c_char,
1251 ret: *mut HostEnt,
1252 buf: *mut c_char,
1253 buflen: usize,
1254 result: *mut *mut HostEnt,
1255 errnop: *mut c_int,
1256) -> c_int {
1257 gethostbyname2_r(name, AF_INET, ret, buf, buflen, result, errnop)
1258}
1259
1260#[no_mangle]
1261pub unsafe extern "C" fn gethostbyname2_r(
1262 name: *const c_char,
1263 af: c_int,
1264 ret: *mut HostEnt,
1265 buf: *mut c_char,
1266 buflen: usize,
1267 result: *mut *mut HostEnt,
1268 errnop: *mut c_int,
1269) -> c_int {
1270 if result.is_null() { return EINVAL; }
1271 *result = core::ptr::null_mut();
1272 let h = gethostbyname2(name, af);
1273 if h.is_null() {
1274 if !errnop.is_null() { *errnop = if h_errno != 0 { h_errno } else { HOST_NOT_FOUND }; }
1275 return 0;
1276 }
1277 let r = host_copy_out(h, ret, buf, buflen, result);
1278 if r == NDB_ERANGE {
1279 if !errnop.is_null() { *errnop = NO_RECOVERY; }
1280 *result = core::ptr::null_mut();
1281 }
1282 r
1283}
1284
1285#[no_mangle]
1286pub unsafe extern "C" fn gethostbyaddr_r(
1287 addr: *const c_void,
1288 len: u32,
1289 type_: c_int,
1290 ret: *mut HostEnt,
1291 buf: *mut c_char,
1292 buflen: usize,
1293 result: *mut *mut HostEnt,
1294 errnop: *mut c_int,
1295) -> c_int {
1296 if result.is_null() { return EINVAL; }
1297 *result = core::ptr::null_mut();
1298 let h = gethostbyaddr(addr, len, type_);
1299 if h.is_null() {
1300 if !errnop.is_null() { *errnop = if h_errno != 0 { h_errno } else { HOST_NOT_FOUND }; }
1301 return 0;
1302 }
1303 let r = host_copy_out(h, ret, buf, buflen, result);
1304 if r == NDB_ERANGE {
1305 if !errnop.is_null() { *errnop = NO_RECOVERY; }
1306 *result = core::ptr::null_mut();
1307 }
1308 r
1309}
1310
1311
1312#[no_mangle]
1313pub unsafe extern "C" fn initgroups(user: *const c_char, group: u32) -> c_int {
1314 if user.is_null() { ERRNO = EINVAL; return -1; }
1315 let mut buf = [0u32; 256];
1316 let mut n: c_int = buf.len() as c_int;
1317 if getgrouplist(user, group, buf.as_mut_ptr(), &mut n) < 0 {
1318 if n <= 0 { return -1; }
1319 let p = crate::malloc(n as usize * core::mem::size_of::<u32>()) as *mut u32;
1320 if p.is_null() { return -1; }
1321 let mut n2 = n;
1322 let r = getgrouplist(user, group, p, &mut n2);
1323 let rr = if r < 0 { -1 } else { crate::setgroups(n2 as usize, p) };
1324 crate::free(p as *mut c_void);
1325 return rr;
1326 }
1327 crate::setgroups(n as usize, buf.as_ptr())
1328}