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