Sortix
Sortix Download Manual Development Source Code News Blog More
current nightly

Sortix nightly manual

This manual documents Sortix nightly, a development build that has not been officially released. You can instead view this document in the latest official manual.

NAME

portability — standard library portability information

DESCRIPTION

This manual documents replacements for interfaces not available in the standard library or with special portability notes.
Software written for other operating systems can be ported by replacing uses of obsolete interfaces with the modern replacements and working around any missing functionality. The standard library attemps to implement the relevant parts of the C and POSIX standards with useful extensions and tends to omit non-standard extensions found on other operating systems whenever standard interfaces exists.

alloca

alloca(3) and variable length arrays are implemented by the compiler, however the main thread stack size is fixed and does not grow unlike other operating systems, and large stack uses should instead use malloc(3) or set the stack size explicitly for another thread using pthread_attr_setstacksize(3).

asctime, asctime_r

strftime(3) is the standard replacement.

bcopy

memcpy(3) is the standard replacement. Note how the order of the source and destination parameters is swapped.

bzero

memset(3) is the standard replacement.

caddr_t

void * is the standard type.

clock

clock(3) is implemented but can overflow, and clock_gettime(2) CLOCK_PROCESS_CPUTIME_ID is the modern replacement with nanosecond precision.

ctime, ctime_r

strftime(3) is the standard replacement.

daemon

Daemons should not background by double forking but rather stay in the foreground as described in daemon(7) and be managed by init(8).

__dead

noreturn from <stdnoreturn.h> is the modern standard replacement or the __attribute__((noreturn)) extension can be used.

flock, fcntl F_UNLCK, F_WRLCK, F_GETLK, F_SETLK, F_SETLKW, lockf

POSIX advisory locks are not implemented due to their flawed design of being process-wide instead of being per file description. The superior flock(2) is not currently implemented. It might be safe enough to omit the file locking as a workaround.

ftime

clock_gettime(2) is the standard replacement.

getdtablesize

The file descriptor table is unbounded and file descriptors above a certain value can be closed using closefrom(2) and iterated using psctl(2).

getgroups, setgroups, initgroups

Supplementary groups are not implemented yet. It may be possible to remove invocations as a workaround.

gethostbyaddr

getnameinfo(3) is the standard modern replacement.

gethostbyname

getaddrinfo(3) is the standard modern replacement.

getitimer, setitimer

timer_create(2) is the modern standard replacement.

getpgrp, setpgrp

getpgid(3) and setpgid(3) are the standard portable replacements without disagreement on the function signatures.

getresgid, getresuid, setresgid, setresuid

These are not implemented yet as multi-user security is not yet implemented in this operating system. The kernel does not have a saved uid and saved gid concept at this time. The getuid(2), getgid(2), geteuid(2), getegid(2), setuid(2), setgid(2), seteuid(2), and setegid(2) system calls can be used to retrieve and manipulate the implemented concepts as a workaround.

gettimeofday

gettimeofday(2) is implemented but the second parameter is defunct and is typed void * per POSIX instead of struct timezone *. clock_gettime(2) is the modern replacement with nanosecond precision.

gid_t

gid_t is 64-bit unsigned and can be formatted portably cast to a uintmax_t using “%ju”.

inet_addr, inet_aton

inet_pton(3) and getaddrinfo(3) are the modern standard replacements, however they don't support the unusual IPv4 notations.

inet_ntoa

inet_ntop(3) and getnameinfo(3) are the modern standard replacements.

<limits.h>

<limits.h> is currently implemented by the compiler instead of the standard library and it does not define everything required by POSIX. <sortix/limits.h> can be included instead as a temporary workaround if the required definitions are absent.

makedev, major, minor

The kernel does not have a concept of major and minor device numbers.

mkfifo

mkfifo(2) named pipes are not currently implemented but unnamed pipes are available using pipe(2), or alternatively AF_UNIX sockets can be used instead.

mknod

Devices in the /dev filesystem are created by the kernel and cannot be manually created.

mmap

mmap(2) is implemented, but MAP_SHARED shared memory mappings are not implemented yet.

off_t

off_t is 64-bit signed and can be formatted portably cast to an intmax_t using “%jd”.

PATH_MAX

The PATH_MAX limit does not currently exist and may be added in the future. Applications should be written as if this limit does not exist, but if required, it can be defined to 4096 as a fallback.

pid_t

pid_t is 64-bit signed and can be formatted portably cast to an intmax_t using “%jd”.

poll

poll(2) is implemented in <poll.h> per POSIX, however some operating systems have a <sys/poll.h> alias which is not implemented.

posix_close

close(2) should be used instead. POSIX 2024 defined this replacement interface because some broken legacy operating systems could fail with EINTR in close(2) on slow devices, instead of returning 0 and either completing the operating in the background or aborting it. However, this means most programs need to be updated to use the more complicated alternative function instead for no practical gain, which isn't going to happen. The standard has added a lot of complexity where none needs to exist, which is rejected in this operating system. close(2) never fails with EINTR on this operating system.

posix_devctl

ioctl(2) should be used instead. POSIX 2024 defined this optional function as a replacement for ioctl(2) but never defined any way for portable applications to actually use it. The dev_info_ptr parameter is especially useless as its semantics are not defined, and often the desired output does not necessarily fit in an int type. The ioctl(2) interface is fine and this alternative function is rejected in this operating system as it is optional in POSIX 2024.

posix_getdents

readdir(3) should be used instead. readdirents(2) is a similar Sortix-specific system call that will likely be replaced with something else in the future. This new posix_getdents function is due to a mess of diverent getdents() functions. It is unfortunate they used struct posix_dent instead of struct dirent as they did not want to mandate the addition of the common d_type field in struct dirent. However, posix_getdents is decent and may be implemented in the future.

printf

printf(3) is implemented, however floating point formatting is not currently implemented and the format specifier will instead be output verbatim. Position parameters are also not implemented yet.

pthread_cancel

Pthread cancellation is not implemented and threads instead have to pthread_exit(3) voluntarily.

pthread_kill

Sending a signal to a particular thread is not implemented.

putenv

setenv(3) is the standard replacement. Note how the string provided could technically be modified at a later time.

rand, srand

rand(3) and srand(3) are implemented, however invocations will warn that the functions are not random, and arc4random(3), arc4random_uniform(3), or arc4random_buf(3) should be used instead for random numbers.

realpath

realpath(3) with a non-null second parameter is undefined behavior as there is no PATH_MAX limit, and should always be invoked with a null second parameter which allocates a destination buffer of the appropriate size using malloc(3).

<resolv.h>

<resolv.h> is currently not implemented and getaddrinfo(2) can be used instead.

sbrk

malloc(3) and mmap(2) are the standard interfaces for memory allocation.

select

select(2) is implemented, but is defined in <sys/select.h> instead of <sys/time.h> per POSIX, however the superior poll(2) should be used instead as the fdset_t type overflows on file descriptors whose value is too large.

sigaction SA_RESTART

Restarting system calls after signal delivery is not currently implemented and system calls instead fail with EINTR.

socklen_t

socklen_t is typedef to size_t instead of int or unsigned int as on other operating systems.

sprintf

sprintf(3) is implemented, however invocations will warn the function is dangerous as it does not know the size of the destination buffer and may buffer overflow if the output is unexpectedly large. snprintf(3) should be use instead as the destination buffer size should always be known, otherwise the invocation is suspicious. The superior alternative is to combine allocation and initialization using asprintf(3).

<sys/param.h>

<sys/param.h> is not implemented as there is little agreement on what it's supposed to contain and all the contents have standard replacements or can be provided by the application itself. Inclusions are almost always unnecessary and can be removed.

times

times(2) is implemented, however the clock_t type may overflow, and the timens(2) non-standard extension with struct timespec precision can be used instead.

time_t

time_t is 64-bit signed and can be formatted portably cast to an intmax_t using “%ji” or with strftime(3) and such.
CLOCK_REALTIME counts the number of seconds since the epoch including leap seconds, unlike other operating systems and in violation of POSIX. CLOCK_REALTIME_HAS_LEAP_SECONDS definition advertises CLOCK_REALTIME contains leap seconds since the epoch in the TAI-10 format.
sub_leap_seconds(3) converts timestamps from TAI-10 to UTC by subtracting the leap seconds, while add_leap_seconds(3) converts timestamps from UTC TO TAI-10 by adding the leap seconds. These functions are useful when communicating with other operating systems either via the network or exchanged data files.

u_char, u_short, u_int, u_long

unsigned char, unsigned short, unsigned int, and unsigned long are the standard types. Applications can supply the typedefs themselves if desired.

uid_t

uid_t is 64-bit unsigned and can be formatted portably cast to a uintmax_t using “%ju”.

u_int8_t, u_int16_t, u_int32_t, u_int64_t

uint8_t, uint16_t, uint32_t, and uint64_t are the standard types. Applications can supply the typedefs themselves if desired.

wait3, wait4

waitpid(2) is the standard replacement.

SEE ALSO

porting(7)
Copyright 2011-2025 Jonas 'Sortie' Termansen and contributors.
Sortix's source code is free software under the ISC license.
#sortix on irc.sortix.org
@sortix_org