xref: /freebsd/stand/libsa/libsa.3 (revision 47ef2a131091508e049ab10cad7f91a3c1342cd9)
1.\" Copyright (c) Michael Smith
2.\" All rights reserved.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions and the following disclaimer.
9.\" 2. Redistributions in binary form must reproduce the above copyright
10.\"    notice, this list of conditions and the following disclaimer in the
11.\"    documentation and/or other materials provided with the distribution.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23.\" SUCH DAMAGE.
24.\"
25.Dd September 9, 2022
26.Dt LIBSA 3
27.Os
28.Sh NAME
29.Nm libsa
30.Nd support library for standalone executables
31.Sh SYNOPSIS
32.In stand.h
33.Sh DESCRIPTION
34The
35.Nm
36library provides a set of supporting functions for standalone
37applications, mimicking where possible the standard
38.Bx
39programming
40environment.
41The following sections group these functions by kind.
42Unless specifically described here, see the corresponding section 3
43manpages for the given functions.
44.Sh STRING FUNCTIONS
45String functions are available as documented in
46.Xr string 3
47and
48.Xr bstring 3 .
49.Sh MEMORY ALLOCATION
50.Bl -hang -width 10n
51.It Xo
52.Ft "void *"
53.Fn malloc "size_t size"
54.Xc
55.Pp
56Allocate
57.Fa size
58bytes of memory from the heap using a best-fit algorithm.
59.It Xo
60.Ft void
61.Fn free "void *ptr"
62.Xc
63.Pp
64Free the allocated object at
65.Fa ptr .
66.It Xo
67.Ft void
68.Fn setheap "void *start" "void *limit"
69.Xc
70.Pp
71Initialise the heap.
72This function must be called before calling
73.Fn alloc
74for the first time.
75The region between
76.Fa start
77and
78.Fa limit
79will be used for the heap; attempting to allocate beyond this will result
80in a panic.
81.It Xo
82.Ft "char *"
83.Fn sbrk "int junk"
84.Xc
85.Pp
86Provides the behaviour of
87.Fn sbrk 0 ,
88i.e., returns the highest point that the heap has reached.
89This value can
90be used during testing to determine the actual heap usage.
91The
92.Fa junk
93argument is ignored.
94.El
95.Sh ENVIRONMENT
96A set of functions are provided for manipulating a flat variable space similar
97to the traditional shell-supported environment.
98Major enhancements are support
99for set/unset hook functions.
100.Bl -hang -width 10n
101.It Xo
102.Ft "char *"
103.Fn getenv "const char *name"
104.Xc
105.It Xo
106.Ft int
107.Fn setenv "const char *name" "const char *value" "int overwrite"
108.Xc
109.It Xo
110.Ft int
111.Fn putenv "char *string"
112.Xc
113.It Xo
114.Ft int
115.Fn unsetenv "const char *name"
116.Xc
117.Pp
118These functions behave similarly to their standard library counterparts.
119.It Xo
120.Ft "struct env_var *"
121.Fn env_getenv "const char *name"
122.Xc
123.Pp
124Looks up a variable in the environment and returns its entire
125data structure.
126.It Xo
127.Ft int
128.Fn env_setenv "const char *name" "int flags" "const void *value" "ev_sethook_t sethook" "ev_unsethook_t unsethook"
129.Xc
130.Pp
131Creates a new or sets an existing environment variable called
132.Fa name .
133If creating a new variable, the
134.Fa sethook
135and
136.Fa unsethook
137arguments may be specified.
138.Pp
139The set hook is invoked whenever an attempt
140is made to set the variable, unless the EV_NOHOOK flag is set.
141Typically
142a set hook will validate the
143.Fa value
144argument, and then call
145.Fn env_setenv
146again with EV_NOHOOK set to actually save the value.
147The predefined function
148.Fn env_noset
149may be specified to refuse all attempts to set a variable.
150.Pp
151The unset hook is invoked when an attempt is made to unset a variable.
152If it
153returns zero, the variable will be unset.
154The predefined function
155.Fa env_nounset
156may be used to prevent a variable being unset.
157.El
158.Sh STANDARD LIBRARY SUPPORT
159.Bl -hang -width 10n
160.It Xo
161.Ft int
162.Fn abs "int i"
163.Xc
164.It Xo
165.Ft int
166.Fn getopt "int argc" "char * const *argv" "const char *optstring"
167.Xc
168.It Xo
169.Ft long
170.Fn strtol "const char *nptr" "char **endptr" "int base"
171.Xc
172.It Xo
173.Ft long long
174.Fn strtoll "const char *nptr" "char **endptr" "int base"
175.Xc
176.It Xo
177.Ft long
178.Fn strtoul "const char *nptr" "char **endptr" "int base"
179.Xc
180.It Xo
181.Ft long long
182.Fn strtoull "const char *nptr" "char **endptr" "int base"
183.Xc
184.It Xo
185.Ft void
186.Fn srandom "unsigned int seed"
187.Xc
188.It Xo
189.Ft "long"
190.Fn random void
191.Xc
192.It Xo
193.Ft "char *"
194.Fn strerror "int error"
195.Xc
196.Pp
197Returns error messages for the subset of errno values supported by
198.Nm .
199.It Fn assert expression
200.Pp
201Requires
202.In assert.h .
203.It Xo
204.Ft int
205.Fn setjmp "jmp_buf env"
206.Xc
207.It Xo
208.Ft void
209.Fn longjmp "jmp_buf env" "int val"
210.Xc
211.Pp
212Defined as
213.Fn _setjmp
214and
215.Fn _longjmp
216respectively as there is no signal state to manipulate.
217Requires
218.In setjmp.h .
219.El
220.Sh CHARACTER I/O
221.Bl -hang -width 10n
222.It Xo
223.Ft void
224.Fn gets "char *buf"
225.Xc
226.Pp
227Read characters from the console into
228.Fa buf .
229All of the standard cautions apply to this function.
230.It Xo
231.Ft void
232.Fn ngets "char *buf" "int size"
233.Xc
234.Pp
235Read at most
236.Fa size
237- 1 characters from the console into
238.Fa buf .
239If
240.Fa size
241is less than 1, the function's behaviour is as for
242.Fn gets .
243.It Xo
244.Ft int
245.Fn fgetstr "char *buf" "int size" "int fd"
246.Xc
247.Pp
248Read a line of at most
249.Fa size
250characters into
251.Fa buf .
252Line terminating characters are stripped, and the buffer is always
253.Dv NUL
254terminated.
255Returns the number of characters in
256.Fa buf
257if successful, or -1 if a read error occurs.
258.It Xo
259.Ft int
260.Fn printf "const char *fmt" "..."
261.Xc
262.It Xo
263.Ft void
264.Fn vprintf "const char *fmt" "va_list ap"
265.Xc
266.It Xo
267.Ft int
268.Fn sprintf "char *buf" "const char *fmt" "..."
269.Xc
270.It Xo
271.Ft void
272.Fn vsprintf "char *buf" "const char *fmt" "va_list ap"
273.Xc
274.Pp
275The *printf functions implement a subset of the standard
276.Fn printf
277family functionality and some extensions.
278The following standard conversions
279are supported: c,d,n,o,p,s,u,x.
280The following modifiers are supported:
281+,-,#,*,0,field width,precision,l.
282.Pp
283The
284.Li b
285conversion is provided to decode error registers.
286Its usage is:
287.Bd -ragged -offset indent
288printf(
289.Qq reg=%b\en ,
290regval,
291.Qq <base><arg>*
292);
293.Ed
294.Pp
295where <base> is the output expressed as a control character, e.g.\& \e10 gives
296octal, \e20 gives hex.
297Each <arg> is a sequence of characters, the first of
298which gives the bit number to be inspected (origin 1) and the next characters
299(up to a character less than 32) give the text to be displayed if the bit is set.
300Thus
301.Bd -ragged -offset indent
302printf(
303.Qq reg=%b\en ,
3043,
305.Qq \e10\e2BITTWO\e1BITONE
306);
307.Ed
308.Pp
309would give the output
310.Bd -ragged -offset indent
311reg=3<BITTWO,BITONE>
312.Ed
313.Pp
314The
315.Li D
316conversion provides a hexdump facility, e.g.
317.Bd -ragged -offset indent
318printf(
319.Qq %6D ,
320ptr,
321.Qq \&:
322); gives
323.Qq XX:XX:XX:XX:XX:XX
324.Ed
325.Bd -ragged -offset indent
326printf(
327.Qq %*D ,
328len,
329ptr,
330.Qq "\ "
331); gives
332.Qq XX XX XX ...
333.Ed
334.El
335.Sh CHARACTER TESTS AND CONVERSIONS
336.Bl -hang -width 10n
337.It Xo
338.Ft int
339.Fn isupper "int c"
340.Xc
341.It Xo
342.Ft int
343.Fn islower "int c"
344.Xc
345.It Xo
346.Ft int
347.Fn isspace "int c"
348.Xc
349.It Xo
350.Ft int
351.Fn isdigit "int c"
352.Xc
353.It Xo
354.Ft int
355.Fn isxdigit "int c"
356.Xc
357.It Xo
358.Ft int
359.Fn isascii "int c"
360.Xc
361.It Xo
362.Ft int
363.Fn isalpha "int c"
364.Xc
365.It Xo
366.Ft int
367.Fn isalnum "int c"
368.Xc
369.It Xo
370.Ft int
371.Fn iscntrl "int c"
372.Xc
373.It Xo
374.Ft int
375.Fn isgraph "int c"
376.Xc
377.It Xo
378.Ft int
379.Fn ispunct "int c"
380.Xc
381.It Xo
382.Ft int
383.Fn toupper "int c"
384.Xc
385.It Xo
386.Ft int
387.Fn tolower "int c"
388.Xc
389.El
390.Sh FILE I/O
391.Bl -hang -width 10n
392.It Xo
393.Ft int
394.Fn open "const char *path" "int flags"
395.Xc
396.Pp
397Similar to the behaviour as specified in
398.Xr open 2 ,
399except that file creation is not supported, so the mode parameter is not
400required.
401The
402.Fa flags
403argument may be one of O_RDONLY, O_WRONLY and O_RDWR.
404Only UFS currently supports writing.
405.It Xo
406.Ft int
407.Fn close "int fd"
408.Xc
409.It Xo
410.Ft void
411.Fn closeall void
412.Xc
413.Pp
414Close all open files.
415.It Xo
416.Ft ssize_t
417.Fn read "int fd" "void *buf" "size_t len"
418.Xc
419.It Xo
420.Ft ssize_t
421.Fn write "int fd" "void *buf" "size_t len"
422.Xc
423.Pp
424(No file systems currently support writing.)
425.It Xo
426.Ft off_t
427.Fn lseek "int fd" "off_t offset" "int whence"
428.Xc
429.Pp
430Files being automatically uncompressed during reading cannot seek backwards
431from the current point.
432.It Xo
433.Ft int
434.Fn stat "const char *path" "struct stat *sb"
435.Xc
436.It Xo
437.Ft int
438.Fn fstat "int fd" "struct stat *sb"
439.Xc
440.Pp
441The
442.Fn stat
443and
444.Fn fstat
445functions only fill out the following fields in the
446.Fa sb
447structure: st_mode,st_nlink,st_uid,st_gid,st_size.
448The
449.Nm tftp
450file system cannot provide meaningful values for this call, and the
451.Nm cd9660
452file system always reports files having uid/gid of zero.
453.El
454.Sh PAGER
455The
456.Nm
457library supplies a simple internal pager to ease reading the output of large
458commands.
459.Bl -hang -width 10n
460.It Xo
461.Ft void
462.Fn pager_open
463.Xc
464.Pp
465Initialises the pager and tells it that the next line output will be the top of the
466display.
467The environment variable LINES is consulted to determine the number of
468lines to be displayed before pausing.
469.It Xo
470.Ft void
471.Fn pager_close void
472.Xc
473.Pp
474Closes the pager.
475.It Xo
476.Ft int
477.Fn pager_output "const char *lines"
478.Xc
479.Pp
480Sends the lines in the
481.Dv NUL Ns
482-terminated buffer at
483.Fa lines
484to the pager.
485Newline characters are counted in order to determine the number
486of lines being output (wrapped lines are not accounted for).
487The
488.Fn pager_output
489function will return zero when all of the lines have been output, or nonzero
490if the display was paused and the user elected to quit.
491.It Xo
492.Ft int
493.Fn pager_file "const char *fname"
494.Xc
495.Pp
496Attempts to open and display the file
497.Fa fname .
498Returns -1 on error, 0 at EOF, or 1 if the user elects to quit while reading.
499.El
500.Sh FEATURE SUPPORT
501A set of functions are provided to communicate support of features from the
502loader binary to the interpreter.
503These are used to do something sensible if we are still operating with a loader
504binary that behaves differently than expected.
505.Bl -hang -width 10n
506.It Xo
507.Ft void
508.Fn feature_enable "uint32_t mask"
509.Xc
510.Pp
511Enable the referenced
512.Fa mask
513feature, which should be one of the
514.Li FEATURE_*
515macros defined in
516.In stand.h .
517.It Xo
518.Ft bool
519.Fn feature_name_is_enabled "const char *name"
520.Xc
521.Pp
522Check if the referenced
523.Fa name
524feature is enabled.
525The
526.Fa name
527is usually the same name as the
528.Li FEATURE_*
529macro, but with the FEATURE_ prefix stripped off.
530The authoritative source of feature names is the mapping table near the top in
531.Pa stand/libsa/features.c .
532.It Xo
533.Ft void
534.Fn "(feature_iter_fn)" "void *cookie" "const char *name" "const char *desc" "bool enabled"
535.Xc
536.Pp
537The
538.Fa cookie
539argument is passed as-is from the argument of the same name to
540.Fn feature_iter .
541The
542.Fa name
543and
544.Fa desc
545arguments are defined in the mapping table in
546.Pa stand/libsa/features.c .
547The
548.Fa enabled
549argument indicates the current status of the feature, though one could
550theoretically turn a feature off in later execution.
551As such, this should likely not be trusted if it is needed after the iteration
552has finished.
553.It Xo
554.Ft void
555.Fn "feature_iter" "feature_iter_fn *iter_fn" "void *cookie"
556.Xc
557.Pp
558Iterate over the current set of features.
559.El
560.Sh MISC
561.Bl -hang -width 10n
562.It Xo
563.Ft char *
564.Fn devformat "struct devdesc *"
565.Xc
566.Pp
567Format the specified device as a string.
568.It Xo
569.Ft int
570.Fn devparse "struct devdesc **dev" "const char *devdesc" "const char **path"
571.Xc
572.Pp
573Parse the
574.Dv devdesc
575string of the form
576.Sq device:[/path/to/file] .
577The
578.Dv devsw
579table is used to match the start of the
580.Sq device
581string with
582.Fa dv_name .
583If
584.Fa dv_parsedev
585is non-NULL, then it will be called to parse the rest of the string and allocate
586the
587.Dv struct devdesc
588for this path.
589If NULL, then a default routine will be called that will allocate a simple
590.Dv struct devdesc ,
591parse a unit number and ensure there's no trailing characters.
592If
593.Dv path
594is non-NULL, then a pointer to the remainder of the
595.Dv devdesc
596string after the device specification is written.
597.It Xo
598.Ft int
599.Fn devinit void
600.Xc
601.Pp
602Calls all the
603.Fa dv_init
604routines in the
605.Dv devsw
606array, returning the number of routines that returned an error.
607.It Xo
608.Ft void
609.Fn twiddle void
610.Xc
611.Pp
612Successive calls emit the characters in the sequence |,/,-,\\ followed by a
613backspace in order to provide reassurance to the user.
614.El
615.Sh REQUIRED LOW-LEVEL SUPPORT
616The following resources are consumed by
617.Nm
618- stack, heap, console and devices.
619.Pp
620The stack must be established before
621.Nm
622functions can be invoked.
623Stack requirements vary depending on the functions
624and file systems used by the consumer and the support layer functions detailed
625below.
626.Pp
627The heap must be established before calling
628.Fn alloc
629or
630.Fn open
631by calling
632.Fn setheap .
633Heap usage will vary depending on the number of simultaneously open files,
634as well as client behaviour.
635Automatic decompression will allocate more
636than 64K of data per open file.
637.Pp
638Console access is performed via the
639.Fn getchar ,
640.Fn putchar
641and
642.Fn ischar
643functions detailed below.
644.Pp
645Device access is initiated via
646.Fn devopen
647and is performed through the
648.Fn dv_strategy ,
649.Fn dv_ioctl
650and
651.Fn dv_close
652functions in the device switch structure that
653.Fn devopen
654returns.
655.Pp
656The consumer must provide the following support functions:
657.Bl -hang -width 10n
658.It Xo
659.Ft int
660.Fn getchar void
661.Xc
662.Pp
663Return a character from the console, used by
664.Fn gets ,
665.Fn ngets
666and pager functions.
667.It Xo
668.Ft int
669.Fn ischar void
670.Xc
671.Pp
672Returns nonzero if a character is waiting from the console.
673.It Xo
674.Ft void
675.Fn putchar int
676.Xc
677.Pp
678Write a character to the console, used by
679.Fn gets ,
680.Fn ngets ,
681.Fn *printf ,
682.Fn panic
683and
684.Fn twiddle
685and thus by many other functions for debugging and informational output.
686.It Xo
687.Ft int
688.Fn devopen "struct open_file *of" "const char *name" "const char **file"
689.Xc
690.Pp
691Open the appropriate device for the file named in
692.Fa name ,
693returning in
694.Fa file
695a pointer to the remaining body of
696.Fa name
697which does not refer to the device.
698The
699.Va f_dev
700field in
701.Fa of
702will be set to point to the
703.Vt devsw
704structure for the opened device if successful.
705Device identifiers must
706always precede the path component, but may otherwise be arbitrarily formatted.
707Used by
708.Fn open
709and thus for all device-related I/O.
710.It Xo
711.Ft int
712.Fn devclose "struct open_file *of"
713.Xc
714.Pp
715Close the device allocated for
716.Fa of .
717The device driver itself will already have been called for the close; this call
718should clean up any allocation made by devopen only.
719.It Xo
720.Ft void
721.Fn __abort
722.Xc
723.Pp
724Calls
725.Fn panic
726with a fixed string.
727.It Xo
728.Ft void
729.Fn panic "const char *msg" "..."
730.Xc
731.Pp
732Signal a fatal and unrecoverable error condition.
733The
734.Fa msg ...
735arguments are as for
736.Fn printf .
737.El
738.Sh INTERNAL FILE SYSTEMS
739Internal file systems are enabled by the consumer exporting the array
740.Vt struct fs_ops *file_system[] ,
741which should be initialised with pointers
742to
743.Vt struct fs_ops
744structures.
745The following file system handlers are supplied by
746.Nm ,
747the consumer may supply other file systems of their own:
748.Bl -hang -width ".Va cd9660_fsops"
749.It Va ufs_fsops
750The
751.Bx
752UFS.
753.It Va ext2fs_fsops
754Linux ext2fs file system.
755.It Va tftp_fsops
756File access via TFTP.
757.It Va nfs_fsops
758File access via NFS.
759.It Va cd9660_fsops
760ISO 9660 (CD-ROM) file system.
761.It Va gzipfs_fsops
762Stacked file system supporting gzipped files.
763When trying the gzipfs file system,
764.Nm
765appends
766.Li .gz
767to the end of the filename, and then tries to locate the file using the other
768file systems.
769Placement of this file system in the
770.Va file_system[]
771array determines whether gzipped files will be opened in preference to non-gzipped
772files.
773It is only possible to seek a gzipped file forwards, and
774.Fn stat
775and
776.Fn fstat
777on gzipped files will report an invalid length.
778.It Va bzipfs_fsops
779The same as
780.Va gzipfs_fsops ,
781but for
782.Xr bzip2 1 Ns -compressed
783files.
784.El
785.Pp
786The array of
787.Vt struct fs_ops
788pointers should be terminated with a NULL.
789.Sh DEVICES
790Devices are exported by the supporting code via the array
791.Vt struct devsw *devsw[]
792which is a NULL terminated array of pointers to device switch structures.
793.Sh DRIVER INTERFACE
794The driver needs to provide a common set of entry points that are
795used by
796.Nm libsa
797to interface with the device.
798.Bd -literal
799struct devsw {
800    const char	dv_name[DEV_NAMLEN];
801    int		dv_type;
802    int		(*dv_init)(void);
803    int		(*dv_strategy)(void *devdata, int rw, daddr_t blk,
804			size_t size, char *buf, size_t *rsize);
805    int		(*dv_open)(struct open_file *f, ...);
806    int		(*dv_close)(struct open_file *f);
807    int		(*dv_ioctl)(struct open_file *f, u_long cmd, void *data);
808    int		(*dv_print)(int verbose);
809    void	(*dv_cleanup)(void);
810    char *	(*dv_fmtdev)(struct devdesc *);
811    int		(*dv_parsedev)(struct devdesc **dev, const char *devpart,
812    		const char **path);
813    bool	(*dv_match)(struct devsw *dv, const char *devspec);
814};
815.Ed
816.Bl -tag -width ".Fn dv_strategy"
817.It Fn dv_name
818The device's name.
819.It Fn dv_type
820Type of device.
821The supported types are:
822.Bl -tag -width "DEVT_NONE"
823.It DEVT_NONE
824.It DEVT_DISK
825.It DEVT_NET
826.It DEVT_CD
827.It DEVT_ZFS
828.It DEVT_FD
829.El
830Each type may have its own associated (struct type_devdesc),
831which has the generic (struct devdesc) as its first member.
832.It Fn dv_init
833Driver initialization routine.
834This routine should probe for available units.
835Drivers are responsible for maintaining lists of units for later enumeration.
836No other driver routines may be called before
837.Fn dv_init
838returns.
839.It Fn dv_open
840The driver open routine.
841.It Fn dv_close
842The driver close routine.
843.It Fn dv_ioctl
844The driver ioctl routine.
845.It Fn dv_print
846Prints information about the available devices.
847Information should be presented with
848.Fn pager_output .
849.It Fn dv_cleanup
850Cleans up any memory used by the device before the next stage is run.
851.It Fn dv_fmtdev
852Converts the specified devdesc to the canonical string representation
853for that device.
854.It Fn dv_parsedev
855Parses the device portion of a file path.
856The
857.Dv devpart
858will point to the
859.Sq tail
860of device name, possibly followed by a colon and a path within the device.
861The
862.Sq tail
863is, by convention, the part of the device specification that follows the
864.Fa dv_name
865part of the string.
866So when
867.Fa devparse
868is parsing the string
869.Dq disk3p5:/xxx ,
870.Dv devpart
871will point to the
872.Sq 3
873in that string.
874The parsing routine is expected to allocate a new
875.Dv struct devdesc
876or subclass and return it in
877.Dv dev
878when successful.
879This routine should set
880.Dv path
881to point to the portion of the string after device specification, or
882.Dq /xxx
883in the earlier example.
884Generally, code needing to parse a path will use
885.Fa devparse
886instead of calling this routine directly.
887.It Fn dv_match
888.Dv NULL
889to specify that all device paths starting with
890.Fa dv_name
891match.
892Otherwise, this function returns 0 for a match and a non-zero
893.Dv errno
894to indicate why it didn't match.
895This is helpful when you claim the device path after using it to query
896properties on systems that have uniform naming for different types of
897devices.
898.El
899.Sh HISTORY
900The
901.Nm
902library contains contributions from many sources, including:
903.Bl -bullet -compact
904.It
905.Nm libsa
906from
907.Nx
908.It
909.Nm libc
910and
911.Nm libkern
912from
913.Fx 3.0 .
914.It
915.Nm zalloc
916from
917.An Matthew Dillon Aq Mt dillon@backplane.com
918.El
919.Pp
920The reorganisation and port to
921.Fx 3.0 ,
922the environment functions and this manpage were written by
923.An Mike Smith Aq Mt msmith@FreeBSD.org .
924.Sh BUGS
925The lack of detailed memory usage data is unhelpful.
926