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