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