1#![no_std]
31#![allow(non_camel_case_types)]
32
33#[cfg(target_os = "windows")]
34compile_error!("libbsd-sys does not support Windows");
35
36use core::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_void};
37
38pub use libc::{FILE, gid_t, mode_t, off_t, pid_t, size_t, ssize_t, uid_t};
40
41unsafe extern "C" {
46 pub fn strlcpy(dst: *mut c_char, src: *const c_char, siz: size_t) -> size_t;
47 pub fn strlcat(dst: *mut c_char, src: *const c_char, siz: size_t) -> size_t;
48 pub fn strnstr(s: *const c_char, find: *const c_char, slen: size_t) -> *mut c_char;
49 pub fn strmode(mode: mode_t, str_: *mut c_char);
50 pub fn explicit_bzero(buf: *mut c_void, len: size_t);
51}
52
53unsafe extern "C" {
58 pub fn arc4random() -> u32;
59 pub fn arc4random_buf(buf: *mut c_void, n: size_t);
60 pub fn arc4random_uniform(upper_bound: u32) -> u32;
61 #[cfg(target_os = "linux")]
62 pub fn arc4random_stir();
63 #[cfg(target_os = "linux")]
64 pub fn arc4random_addrandom(dat: *mut c_uchar, datlen: c_int);
65
66 #[cfg(target_os = "linux")]
67 pub fn dehumanize_number(str_: *const c_char, size: *mut i64) -> c_int;
68
69 pub fn getprogname() -> *const c_char;
70 pub fn setprogname(name: *const c_char);
71
72 pub fn heapsort(
73 base: *mut c_void,
74 nmemb: size_t,
75 size: size_t,
76 cmp: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
77 ) -> c_int;
78 pub fn mergesort(
79 base: *mut c_void,
80 nmemb: size_t,
81 size: size_t,
82 cmp: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
83 ) -> c_int;
84 pub fn radixsort(
85 base: *mut *const c_uchar,
86 nmemb: c_int,
87 table: *const c_uchar,
88 endbyte: c_uint,
89 ) -> c_int;
90 pub fn sradixsort(
91 base: *mut *const c_uchar,
92 nmemb: c_int,
93 table: *const c_uchar,
94 endbyte: c_uint,
95 ) -> c_int;
96
97 pub fn reallocf(ptr: *mut c_void, size: size_t) -> *mut c_void;
98 pub fn reallocarray(ptr: *mut c_void, nmemb: size_t, size: size_t) -> *mut c_void;
99 #[cfg(not(target_os = "macos"))]
100 pub fn recallocarray(
101 ptr: *mut c_void,
102 oldnmemb: size_t,
103 nmemb: size_t,
104 size: size_t,
105 ) -> *mut c_void;
106 #[cfg(not(target_os = "macos"))]
107 pub fn freezero(ptr: *mut c_void, size: size_t);
108
109 pub fn strtonum(
110 nptr: *const c_char,
111 minval: i64,
112 maxval: i64,
113 errstr: *mut *const c_char,
114 ) -> i64;
115
116 pub fn getbsize(headerlenp: *mut c_int, blocksizep: *mut c_long) -> *mut c_char;
117}
118
119unsafe extern "C" {
124 pub static mut optreset: c_int;
125
126 #[cfg(target_os = "linux")]
127 pub fn bsd_getopt(argc: c_int, argv: *const *mut c_char, shortopts: *const c_char) -> c_int;
128
129 pub fn getmode(set: *const c_void, mode: mode_t) -> mode_t;
130 pub fn setmode(mode_str: *const c_char) -> *mut c_void;
131
132 pub fn closefrom(lowfd: c_int);
133
134 #[cfg(target_os = "linux")]
135 pub fn setproctitle_init(argc: c_int, argv: *mut *mut c_char, envp: *mut *mut c_char);
136 #[cfg(not(target_os = "macos"))]
137 pub fn setproctitle(fmt: *const c_char, ...);
138
139 pub fn getpeereid(s: c_int, euid: *mut uid_t, egid: *mut gid_t) -> c_int;
140}
141
142unsafe extern "C" {
147 pub fn fmtcheck(f1: *const c_char, f2: *const c_char) -> *const c_char;
148
149 pub fn fgetln(fp: *mut FILE, lenp: *mut size_t) -> *mut c_char;
150
151 pub fn funopen(
152 cookie: *const c_void,
153 readfn: Option<unsafe extern "C" fn(*mut c_void, *mut c_char, c_int) -> c_int>,
154 writefn: Option<unsafe extern "C" fn(*mut c_void, *const c_char, c_int) -> c_int>,
155 seekfn: Option<unsafe extern "C" fn(*mut c_void, off_t, c_int) -> off_t>,
156 closefn: Option<unsafe extern "C" fn(*mut c_void) -> c_int>,
157 ) -> *mut FILE;
158
159 pub fn fpurge(fp: *mut FILE) -> c_int;
160}
161
162pub const RPP_ECHO_OFF: c_int = 0x00;
167pub const RPP_ECHO_ON: c_int = 0x01;
168pub const RPP_REQUIRE_TTY: c_int = 0x02;
169pub const RPP_FORCELOWER: c_int = 0x04;
170pub const RPP_FORCEUPPER: c_int = 0x08;
171pub const RPP_SEVENBIT: c_int = 0x10;
172pub const RPP_STDIN: c_int = 0x20;
173
174unsafe extern "C" {
175 pub fn readpassphrase(
176 prompt: *const c_char,
177 buf: *mut c_char,
178 bufsiz: size_t,
179 flags: c_int,
180 ) -> *mut c_char;
181}
182
183pub const VIS_OCTAL: c_int = 0x0001;
188pub const VIS_CSTYLE: c_int = 0x0002;
189pub const VIS_SP: c_int = 0x0004;
190pub const VIS_TAB: c_int = 0x0008;
191pub const VIS_NL: c_int = 0x0010;
192pub const VIS_WHITE: c_int = VIS_SP | VIS_TAB | VIS_NL;
193pub const VIS_SAFE: c_int = 0x0020;
194pub const VIS_DQ: c_int = 0x8000;
195pub const VIS_NOSLASH: c_int = 0x0040;
196pub const VIS_HTTP1808: c_int = 0x0080;
197pub const VIS_HTTPSTYLE: c_int = 0x0080;
198pub const VIS_MIMESTYLE: c_int = 0x0100;
199pub const VIS_HTTP1866: c_int = 0x0200;
200pub const VIS_NOESCAPE: c_int = 0x0400;
201pub const VIS_GLOB: c_int = 0x1000;
202pub const VIS_SHELL: c_int = 0x2000;
203pub const VIS_META: c_int = VIS_WHITE | VIS_GLOB | VIS_SHELL;
204pub const VIS_NOLOCALE: c_int = 0x4000;
205
206pub const UNVIS_VALID: c_int = 1;
207pub const UNVIS_VALIDPUSH: c_int = 2;
208pub const UNVIS_NOCHAR: c_int = 3;
209pub const UNVIS_SYNBAD: c_int = -1;
210pub const UNVIS_ERROR: c_int = -2;
211pub const UNVIS_END: c_int = 0x0800;
212
213unsafe extern "C" {
214 pub fn vis(dst: *mut c_char, c: c_int, flag: c_int, nextc: c_int) -> *mut c_char;
215 pub fn nvis(dst: *mut c_char, dlen: size_t, c: c_int, flag: c_int, nextc: c_int)
216 -> *mut c_char;
217
218 pub fn svis(
219 dst: *mut c_char,
220 c: c_int,
221 flag: c_int,
222 nextc: c_int,
223 extra: *const c_char,
224 ) -> *mut c_char;
225 pub fn snvis(
226 dst: *mut c_char,
227 dlen: size_t,
228 c: c_int,
229 flag: c_int,
230 nextc: c_int,
231 extra: *const c_char,
232 ) -> *mut c_char;
233
234 pub fn strvis(dst: *mut c_char, src: *const c_char, flag: c_int) -> c_int;
235 pub fn stravis(dst: *mut *mut c_char, src: *const c_char, flag: c_int) -> c_int;
236 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
240 pub fn strnvis(dst: *mut c_char, src: *const c_char, dlen: size_t, flag: c_int) -> c_int;
241 #[cfg(any(target_os = "macos", target_os = "netbsd", target_os = "openbsd"))]
242 pub fn strnvis(dst: *mut c_char, dlen: size_t, src: *const c_char, flag: c_int) -> c_int;
243
244 pub fn strsvis(
245 dst: *mut c_char,
246 src: *const c_char,
247 flag: c_int,
248 extra: *const c_char,
249 ) -> c_int;
250 pub fn strsnvis(
251 dst: *mut c_char,
252 dlen: size_t,
253 src: *const c_char,
254 flag: c_int,
255 extra: *const c_char,
256 ) -> c_int;
257
258 pub fn strvisx(dst: *mut c_char, src: *const c_char, len: size_t, flag: c_int) -> c_int;
259 pub fn strnvisx(
260 dst: *mut c_char,
261 dlen: size_t,
262 src: *const c_char,
263 len: size_t,
264 flag: c_int,
265 ) -> c_int;
266 pub fn strenvisx(
267 dst: *mut c_char,
268 dlen: size_t,
269 src: *const c_char,
270 len: size_t,
271 flag: c_int,
272 cerr_ptr: *mut c_int,
273 ) -> c_int;
274
275 pub fn strsvisx(
276 dst: *mut c_char,
277 src: *const c_char,
278 len: size_t,
279 flag: c_int,
280 extra: *const c_char,
281 ) -> c_int;
282 pub fn strsnvisx(
283 dst: *mut c_char,
284 dlen: size_t,
285 src: *const c_char,
286 len: size_t,
287 flag: c_int,
288 extra: *const c_char,
289 ) -> c_int;
290 pub fn strsenvisx(
291 dst: *mut c_char,
292 dlen: size_t,
293 src: *const c_char,
294 len: size_t,
295 flag: c_int,
296 extra: *const c_char,
297 cerr_ptr: *mut c_int,
298 ) -> c_int;
299
300 pub fn strunvis(dst: *mut c_char, src: *const c_char) -> c_int;
301 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
302 pub fn strnunvis(dst: *mut c_char, src: *const c_char, dlen: size_t) -> ssize_t;
303 #[cfg(any(target_os = "macos", target_os = "netbsd", target_os = "openbsd"))]
304 pub fn strnunvis(dst: *mut c_char, dlen: size_t, src: *const c_char) -> c_int;
305
306 pub fn strunvisx(dst: *mut c_char, src: *const c_char, flag: c_int) -> c_int;
307 pub fn strnunvisx(dst: *mut c_char, dlen: size_t, src: *const c_char, flag: c_int) -> c_int;
308
309 pub fn unvis(cp: *mut c_char, c: c_int, apts: *mut c_int, flag: c_int) -> c_int;
310}
311
312#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
317pub const HN_DECIMAL: c_int = 0x01;
318#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
319pub const HN_NOSPACE: c_int = 0x02;
320#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
321pub const HN_B: c_int = 0x04;
322#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
323pub const HN_DIVISOR_1000: c_int = 0x08;
324#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
325pub const HN_IEC_PREFIXES: c_int = 0x10;
326#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
327pub const HN_GETSCALE: c_int = 0x10;
328#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
329pub const HN_AUTOSCALE: c_int = 0x20;
330
331pub const FPARSELN_UNESCESC: c_int = 0x01;
332pub const FPARSELN_UNESCCONT: c_int = 0x02;
333pub const FPARSELN_UNESCCOMM: c_int = 0x04;
334pub const FPARSELN_UNESCREST: c_int = 0x08;
335pub const FPARSELN_UNESCALL: c_int = 0x0f;
336
337#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
338#[repr(C)]
339pub struct pidfh {
340 _opaque: [u8; 0],
341}
342
343#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
344unsafe extern "C" {
345 pub fn humanize_number(
346 buf: *mut c_char,
347 len: size_t,
348 bytes: i64,
349 suffix: *const c_char,
350 scale: c_int,
351 flags: c_int,
352 ) -> c_int;
353 pub fn expand_number(buf: *const c_char, num: *mut u64) -> c_int;
354
355 pub fn flopen(path: *const c_char, flags: c_int, ...) -> c_int;
356 pub fn flopenat(dirfd: c_int, path: *const c_char, flags: c_int, ...) -> c_int;
357
358 pub fn pidfile_open(path: *const c_char, mode: mode_t, pidptr: *mut pid_t) -> *mut pidfh;
359 pub fn pidfile_fileno(pfh: *const pidfh) -> c_int;
360 pub fn pidfile_write(pfh: *mut pidfh) -> c_int;
361 pub fn pidfile_close(pfh: *mut pidfh) -> c_int;
362 pub fn pidfile_remove(pfh: *mut pidfh) -> c_int;
363}
364
365unsafe extern "C" {
366 pub fn fparseln(
367 fp: *mut FILE,
368 size: *mut size_t,
369 lineno: *mut size_t,
370 delim: *const [c_char; 3],
371 flags: c_int,
372 ) -> *mut c_char;
373}
374
375#[cfg(not(target_os = "macos"))]
381#[repr(C)]
382pub struct nlist {
383 pub n_name: *mut c_char,
384 pub n_type: u8,
385 pub n_other: c_char,
386 pub n_desc: i16,
387 pub n_value: c_ulong,
388}
389
390pub use core::ffi::c_ulong;
391
392pub const N_UNDF: u8 = 0x00;
393pub const N_ABS: u8 = 0x02;
394pub const N_TEXT: u8 = 0x04;
395pub const N_DATA: u8 = 0x06;
396pub const N_BSS: u8 = 0x08;
397pub const N_INDR: u8 = 0x0a;
398pub const N_SIZE: u8 = 0x0c;
399pub const N_COMM: u8 = 0x12;
400pub const N_SETA: u8 = 0x14;
401pub const N_SETT: u8 = 0x16;
402pub const N_SETD: u8 = 0x18;
403pub const N_SETB: u8 = 0x1a;
404pub const N_SETV: u8 = 0x1c;
405pub const N_FN: u8 = 0x1e;
406pub const N_WARN: u8 = 0x1e;
407pub const N_EXT: u8 = 0x01;
408pub const N_TYPE: u8 = 0x1e;
409pub const N_STAB: u8 = 0xe0;
410
411#[cfg(not(target_os = "macos"))]
412unsafe extern "C" {
413 pub fn nlist(filename: *const c_char, list: *mut nlist) -> c_int;
414}
415
416#[repr(C)]
421pub struct StringList {
422 pub sl_str: *mut *mut c_char,
423 pub sl_max: size_t,
424 pub sl_cur: size_t,
425}
426
427unsafe extern "C" {
428 pub fn sl_init() -> *mut StringList;
429 pub fn sl_add(sl: *mut StringList, item: *mut c_char) -> c_int;
430 pub fn sl_free(sl: *mut StringList, freel: c_int);
431 pub fn sl_find(sl: *mut StringList, name: *const c_char) -> *mut c_char;
432 #[cfg(target_os = "linux")]
433 pub fn sl_delete(sl: *mut StringList, name: *const c_char, freel: c_int) -> c_int;
434}
435
436#[cfg(target_os = "linux")]
441unsafe extern "C" {
442 #[link_name = "_time32_to_time"]
443 pub fn time32_to_time(t32: i32) -> libc::time_t;
444 #[link_name = "_time_to_time32"]
445 pub fn time_to_time32(t: libc::time_t) -> i32;
446 #[link_name = "_time64_to_time"]
447 pub fn time64_to_time(t64: i64) -> libc::time_t;
448 #[link_name = "_time_to_time64"]
449 pub fn time_to_time64(t: libc::time_t) -> i64;
450 #[link_name = "_time_to_long"]
451 pub fn time_to_long(t: libc::time_t) -> c_long;
452 #[link_name = "_long_to_time"]
453 pub fn long_to_time(tlong: c_long) -> libc::time_t;
454 #[link_name = "_time_to_int"]
455 pub fn time_to_int(t: libc::time_t) -> c_int;
456 #[link_name = "_int_to_time"]
457 pub fn int_to_time(tint: c_int) -> libc::time_t;
458}
459
460unsafe extern "C" {
465 pub fn warnc(code: c_int, format: *const c_char, ...);
466 pub fn errc(status: c_int, code: c_int, format: *const c_char, ...) -> !;
467}
468
469unsafe extern "C" {
474 pub fn fgetwln(stream: *mut FILE, len: *mut size_t) -> *mut libc::wchar_t;
475 pub fn wcslcat(dst: *mut libc::wchar_t, src: *const libc::wchar_t, size: size_t) -> size_t;
476 pub fn wcslcpy(dst: *mut libc::wchar_t, src: *const libc::wchar_t, size: size_t) -> size_t;
477}
478
479unsafe extern "C" {
484 pub fn gid_from_group(name: *const c_char, gid: *mut gid_t) -> c_int;
485 pub fn group_from_gid(gid: gid_t, nosuchgroup: c_int) -> *const c_char;
486}
487
488unsafe extern "C" {
493 pub fn uid_from_user(name: *const c_char, uid: *mut uid_t) -> c_int;
494 pub fn user_from_uid(uid: uid_t, nosuchuser: c_int) -> *const c_char;
495}
496
497unsafe extern "C" {
502 pub fn inet_net_pton(af: c_int, src: *const c_char, dst: *mut c_void, size: size_t) -> c_int;
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508
509 #[test]
510 fn smoke_arc4random() {
511 unsafe {
512 let _ = arc4random();
513 }
514 }
515
516 #[test]
517 fn smoke_strlcpy() {
518 let src = b"hello\0";
519 let mut dst = [0u8; 16];
520 unsafe {
521 let n = strlcpy(
522 dst.as_mut_ptr().cast(),
523 src.as_ptr().cast(),
524 dst.len() as size_t,
525 );
526 assert_eq!(n, 5);
527 assert_eq!(&dst[..6], b"hello\0");
528 }
529 }
530
531 #[test]
532 #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
533 fn smoke_humanize_number() {
534 let mut buf = [0u8; 16];
535 unsafe {
536 let ret = humanize_number(
537 buf.as_mut_ptr().cast(),
538 buf.len() as size_t,
539 1024 * 1024,
540 b"\0".as_ptr().cast(),
541 HN_AUTOSCALE,
542 HN_DECIMAL | HN_NOSPACE | HN_B,
543 );
544 assert!(ret >= 0);
545 }
546 }
547
548 #[test]
549 fn smoke_arc4random_uniform() {
550 unsafe {
551 let val = arc4random_uniform(100);
552 assert!(val < 100);
553 }
554 }
555
556 #[test]
557 fn smoke_strtonum() {
558 let s = b"42\0";
559 let mut errstr: *const c_char = core::ptr::null();
560 unsafe {
561 let val = strtonum(s.as_ptr().cast(), 0, 100, &mut errstr);
562 assert_eq!(val, 42);
563 assert!(errstr.is_null());
564 }
565 }
566
567 #[test]
568 fn smoke_getprogname() {
569 unsafe {
570 let name = getprogname();
571 assert!(!name.is_null());
572 }
573 }
574
575 #[test]
576 fn smoke_vis_str() {
577 let src = b"hello\tworld\0";
578 let mut dst = [0u8; 64];
579 unsafe {
580 let ret = strvis(dst.as_mut_ptr().cast(), src.as_ptr().cast(), VIS_TAB);
581 assert!(ret > 0);
582 }
583 }
584}