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 600Calls all the 601.Fa dv_init 602routines in the 603.Dv devsw 604array, returning the number of routines that returned an error. 605.It Xo 606.Ft void 607.Fn twiddle void 608.Xc 609.Pp 610Successive calls emit the characters in the sequence |,/,-,\\ followed by a 611backspace in order to provide reassurance to the user. 612.El 613.Sh REQUIRED LOW-LEVEL SUPPORT 614The following resources are consumed by 615.Nm 616- stack, heap, console and devices. 617.Pp 618The stack must be established before 619.Nm 620functions can be invoked. 621Stack requirements vary depending on the functions 622and file systems used by the consumer and the support layer functions detailed 623below. 624.Pp 625The heap must be established before calling 626.Fn alloc 627or 628.Fn open 629by calling 630.Fn setheap . 631Heap usage will vary depending on the number of simultaneously open files, 632as well as client behaviour. 633Automatic decompression will allocate more 634than 64K of data per open file. 635.Pp 636Console access is performed via the 637.Fn getchar , 638.Fn putchar 639and 640.Fn ischar 641functions detailed below. 642.Pp 643Device access is initiated via 644.Fn devopen 645and is performed through the 646.Fn dv_strategy , 647.Fn dv_ioctl 648and 649.Fn dv_close 650functions in the device switch structure that 651.Fn devopen 652returns. 653.Pp 654The consumer must provide the following support functions: 655.Bl -hang -width 10n 656.It Xo 657.Ft int 658.Fn getchar void 659.Xc 660.Pp 661Return a character from the console, used by 662.Fn gets , 663.Fn ngets 664and pager functions. 665.It Xo 666.Ft int 667.Fn ischar void 668.Xc 669.Pp 670Returns nonzero if a character is waiting from the console. 671.It Xo 672.Ft void 673.Fn putchar int 674.Xc 675.Pp 676Write a character to the console, used by 677.Fn gets , 678.Fn ngets , 679.Fn *printf , 680.Fn panic 681and 682.Fn twiddle 683and thus by many other functions for debugging and informational output. 684.It Xo 685.Ft int 686.Fn devopen "struct open_file *of" "const char *name" "const char **file" 687.Xc 688.Pp 689Open the appropriate device for the file named in 690.Fa name , 691returning in 692.Fa file 693a pointer to the remaining body of 694.Fa name 695which does not refer to the device. 696The 697.Va f_dev 698field in 699.Fa of 700will be set to point to the 701.Vt devsw 702structure for the opened device if successful. 703Device identifiers must 704always precede the path component, but may otherwise be arbitrarily formatted. 705Used by 706.Fn open 707and thus for all device-related I/O. 708.It Xo 709.Ft int 710.Fn devclose "struct open_file *of" 711.Xc 712.Pp 713Close the device allocated for 714.Fa of . 715The device driver itself will already have been called for the close; this call 716should clean up any allocation made by devopen only. 717.It Xo 718.Ft void 719.Fn __abort 720.Xc 721.Pp 722Calls 723.Fn panic 724with a fixed string. 725.It Xo 726.Ft void 727.Fn panic "const char *msg" "..." 728.Xc 729.Pp 730Signal a fatal and unrecoverable error condition. 731The 732.Fa msg ... 733arguments are as for 734.Fn printf . 735.El 736.Sh INTERNAL FILE SYSTEMS 737Internal file systems are enabled by the consumer exporting the array 738.Vt struct fs_ops *file_system[] , 739which should be initialised with pointers 740to 741.Vt struct fs_ops 742structures. 743The following file system handlers are supplied by 744.Nm , 745the consumer may supply other file systems of their own: 746.Bl -hang -width ".Va cd9660_fsops" 747.It Va ufs_fsops 748The 749.Bx 750UFS. 751.It Va ext2fs_fsops 752Linux ext2fs file system. 753.It Va tftp_fsops 754File access via TFTP. 755.It Va nfs_fsops 756File access via NFS. 757.It Va cd9660_fsops 758ISO 9660 (CD-ROM) file system. 759.It Va gzipfs_fsops 760Stacked file system supporting gzipped files. 761When trying the gzipfs file system, 762.Nm 763appends 764.Li .gz 765to the end of the filename, and then tries to locate the file using the other 766file systems. 767Placement of this file system in the 768.Va file_system[] 769array determines whether gzipped files will be opened in preference to non-gzipped 770files. 771It is only possible to seek a gzipped file forwards, and 772.Fn stat 773and 774.Fn fstat 775on gzipped files will report an invalid length. 776.It Va bzipfs_fsops 777The same as 778.Va gzipfs_fsops , 779but for 780.Xr bzip2 1 Ns -compressed 781files. 782.El 783.Pp 784The array of 785.Vt struct fs_ops 786pointers should be terminated with a NULL. 787.Sh DEVICES 788Devices are exported by the supporting code via the array 789.Vt struct devsw *devsw[] 790which is a NULL terminated array of pointers to device switch structures. 791.Sh DRIVER INTERFACE 792The driver needs to provide a common set of entry points that are 793used by 794.Nm libsa 795to interface with the device. 796.Bd -literal 797struct devsw { 798 const char dv_name[DEV_NAMLEN]; 799 int dv_type; 800 int (*dv_init)(void); 801 int (*dv_strategy)(void *devdata, int rw, daddr_t blk, 802 size_t size, char *buf, size_t *rsize); 803 int (*dv_open)(struct open_file *f, ...); 804 int (*dv_close)(struct open_file *f); 805 int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data); 806 int (*dv_print)(int verbose); 807 void (*dv_cleanup)(void); 808 char * (*dv_fmtdev)(struct devdesc *); 809 int (*dv_parsedev)(struct devdesc **dev, const char *devpart, 810 const char **path); 811 bool (*dv_match)(struct devsw *dv, const char *devspec); 812}; 813.Ed 814.Bl -tag -width ".Fn dv_strategy" 815.It Fn dv_name 816The device's name. 817.It Fn dv_type 818Type of device. 819The supported types are: 820.Bl -tag -width "DEVT_NONE" 821.It DEVT_NONE 822.It DEVT_DISK 823.It DEVT_NET 824.It DEVT_CD 825.It DEVT_ZFS 826.It DEVT_FD 827.El 828Each type may have its own associated (struct type_devdesc), 829which has the generic (struct devdesc) as its first member. 830.It Fn dv_init 831Driver initialization routine. 832This routine should probe for available units. 833Drivers are responsible for maintaining lists of units for later enumeration. 834No other driver routines may be called before 835.Fn dv_init 836returns. 837.It Fn dv_open 838The driver open routine. 839.It Fn dv_close 840The driver close routine. 841.It Fn dv_ioctl 842The driver ioctl routine. 843.It Fn dv_print 844Prints information about the available devices. 845Information should be presented with 846.Fn pager_output . 847.It Fn dv_cleanup 848Cleans up any memory used by the device before the next stage is run. 849.It Fn dv_fmtdev 850Converts the specified devdesc to the canonical string representation 851for that device. 852.It Fn dv_parsedev 853Parses the device portion of a file path. 854The 855.Dv devpart 856will point to the 857.Sq tail 858of device name, possibly followed by a colon and a path within the device. 859The 860.Sq tail 861is, by convention, the part of the device specification that follows the 862.Fa dv_name 863part of the string. 864So when 865.Fa devparse 866is parsing the string 867.Dq disk3p5:/xxx , 868.Dv devpart 869will point to the 870.Sq 3 871in that string. 872The parsing routine is expected to allocate a new 873.Dv struct devdesc 874or subclass and return it in 875.Dv dev 876when successful. 877This routine should set 878.Dv path 879to point to the portion of the string after device specification, or 880.Dq /xxx 881in the earlier example. 882Generally, code needing to parse a path will use 883.Fa devparse 884instead of calling this routine directly. 885.It Fn dv_match 886.Dv NULL 887to specify that all device paths starting with 888.Fa dv_name 889match. 890Otherwise, this function returns 0 for a match and a non-zero 891.Dv errno 892to indicate why it didn't match. 893This is helpful when you claim the device path after using it to query 894properties on systems that have uniform naming for different types of 895devices. 896.El 897.Sh HISTORY 898The 899.Nm 900library contains contributions from many sources, including: 901.Bl -bullet -compact 902.It 903.Nm libsa 904from 905.Nx 906.It 907.Nm libc 908and 909.Nm libkern 910from 911.Fx 3.0 . 912.It 913.Nm zalloc 914from 915.An Matthew Dillon Aq Mt dillon@backplane.com 916.El 917.Pp 918The reorganisation and port to 919.Fx 3.0 , 920the environment functions and this manpage were written by 921.An Mike Smith Aq Mt msmith@FreeBSD.org . 922.Sh BUGS 923The lack of detailed memory usage data is unhelpful. 924