Title: Unix Systems Porting Guidelines Status: Work In Progress Author: Guillem Jover Last-Change: 2015-01-17 Documentation ============= Pre-defined C/C++ Compiler Macros --------------------------------- __GNU_LIBRARY__ 1 → 2 → 3 → 4 → 5 → __GLIBC__ == 1 6 → __GLIBC__ == 2 Porting guidelines (to be merged) ------------------ Just a skeleton for now. Porting issues -------------- Functionality Equivalence (organize into sections) ========================= get_current_dir_name() ---------------------- GNU extension, available on GNU/*. On FreeBSD and GNU/* getcwd(NULL, 0) allocates. canonicalize_file_name() ------------------------ GNU extension, available on GNU/*. On FreeBSD and GNU/* realpath(path, NULL) allocates (POSIX.1-2008). fgetln() -------- BSD extension, supported. On GNU/* libbsd provides it. On POSIX.1-2008 or GNU/* getline() can be used instead. timerfd, signalfd, epoll, inotify, fanotify ------------------------------------------- On FreeBSD, GNU/kFreeBSD, DragonflyBSD, NetBSD, OpenBSD and Darwin kqueue . Darwin has O_EVTONLY, which can be used on file descriptors to monitor so that it does not make the mount busy. On GNU/Linux and Solaris libkqueue . On GNU/Hurd file and directory notify support. Processes notification ---------------------- On Unix ptrace(2). On BSD kqueue(2). On Linux proc netfilter connector (with BFP socket filtering) /proc/PID/{stat,comm,cmdline,root,fd/} -------------------------------------- On FreeBSD, GNU/kFreeBSD, DragonflyBSD, NetBSD, OpenBSD and Darwin libkvm . On GNU/Hurd proc_stat . prctl() PR_SET_NAME ------------------- On FreeBSD and GNU/kFreeBSD libkvm or setprogname(). On GNU/* libbsd provides setprogname(). prctl() PR_SET_CHILD_SUBREAPER / PR_GET_CHILD_SUBREAPER ------------------------------------------------------- On FreeBSD and DragonFlyBSD procctl(2) PROC_REAP_ACQUIRE, PROC_REAP_RELEASE, PROC_REAP_STATUS, PROC_REAP_GETPIDS, PROC_REAP_KILL. Clearing environ variable ------------------------- libudev ------- On FreeBSD or GNU/kFreeBSD devd's socket (libdevstat, libdevinfo). On OpenBSD hotplugd. On NetBSD devmon (not implemented yet). On Solaris sysevent. setsockopt(IP_FREEBIND) ----------------------- On BSDs setsockopt(IP_BINDANY). setsockopt(IP_PKTINFO) ---------------------- On BSDs and Solaris IP_RECVDSTADDR, IP_SENDSRCADDR. setsockopt(IP_TRANSPORT) ------------------------ ?? setsockopt(TCP_KEEPIDLE) ------------------------ On FreeBSD setsockopt(SO_KEEPALIVE). O_CLOEXEC/SOCK_CLOEXEC ---------------------- On POSIX.1-2008 systems, supported. Otherwise fcntl(FD_CLOEXEC), although can be racy on threaded programs, if no precautions are taken. F_SETPIPE_SZ ------------ On FreeBSD and GNU/kFreeBSD, not needed, it uses adaptive pipe sizes. POSIX mqueue as fd ------------------ On FreeBSD and GNU/kFreeBSD, supported. POSIX openat() and friends -------------------------- On FreeBSD and GNU/kFreeBSD, supported. *asprintf() ----------- On GNU/*, BSDs, OpenSolaris, Mac OS X, supported. /dev/urandom ------------ On BSDs, supported, just a symlink to /dev/random which never blocks. On GNU/Hurd, supported through random-egd. AF_UNIX/SOCK_SEQPACKET ---------------------- On FreeBSD and GNU/kFreeBSD, supported. Otherwise SOCK_DGRAM might be a viable replacement. Abstract namespace AF_UNIX -------------------------- On non-Linux, either using non abstract AF_UNIX, or AF_INET loopback could be used instead. Resource limits (RLIMIT_RTTIME / RLIMIT_RTPRIO) --------------- Clearly optional. Resource limits (SCHED_RESET_ON_FORK) --------------- ?? Resource limits (ioprio / ionice) --------------- Clearly optional. Resource limits (OOM score adjustment) --------------- Clearly optional. O_DIRECTORY ----------- On POSIX.1-2008 systems, supported. Otherwise can be replaced by standard usage of stat() to verify it's a dir (although racy), or by rmdir() and errno == ENOTDIR followed by unlink(), etc. Console: Setting keyboard mode ------------------------------ On Linux, FreeBSD and GNU/kFreeBSD: ioctl KDSKBMODE Console: Clearing scrollback buffer ----------------------------------- On Linux >= 2.6.40: \033[3J On FreeBSD and GNU/kFreeBSD: ioctl CONS_CLRHIST Terminal: Setting non-exclusive mode ------------------------------------ On Linux, FreeBSD and GNU/kFreeBSD: ioctl TIOCNXCL Console: Managing controlling tty --------------------------------- On Linux, FreeBSD and GNU/kFreeBSD: ioctl TIOCSCTTY/TIOCNOTTY Console: Activate a specific vty -------------------------------- On Linux, FreeBSD and GNU/kFreeBSD: ioctl VT_ACTIVATE Console: Get current active vty ------------------------------- On Linux: /dev/tty0 On FreeBSD and GNU/kFreeBSD: ioctl VT_GETACTIVE Console: Get system console --------------------------- On Linux: /sys/class/tty/console/active Console: Cleanup tty for next login ----------------------------------- On Linux: ioctl TIOCVHANGUP Console: ioctl TIOCLINUX(TIOCL_GETKMSGREDIRECT) ----------------------------------------------- ?? SELinux ------- On FreeBSD the MAC and Audit frameworks. Linux audit ----------- ?? cgroups and /proc/PID/cgroup ---------------------------- On FreeBSD, jail(2). POSIX capabilities (not to be confused with capability-based security) ------------------ On FreeBSD, depending on the usage with jail(2). prctl() PR_CAPBSET_DROP ----------------------- On FreeBSD, depending on the usage with jail(2). waitid() -------- On POSIX.1-2008 systems supported. On kqueue supported systems, can be replaced with EVFILT_PROC. prctl() PR_SET_PDEATHSIG / PR_GET_PDEATHSIG ------------------------------------------- ?? /proc/cmdline (kernel command line) ------------- On FreeBSD and GNU/kFreeBSD: The boot loader can set arbitrary environment variables. Kernel flags in sysctl debug.boothowto. Other flags passed to init. /sys/class/dmi/id ----------------- On FreeBSD: sysctl smbios.* Otherwise the dmidecode program can be used instead. /dev/rtc -------- On FreeBSD and GNU/kFreeBSD: rtc kernel module from ports collection Device access by major:minor ---------------------------- On Linux: /dev/char/*, /dev/block/* ?? Device access by volume label ----------------------------- On Linux (older udev?): /dev/disk/by-label/* ?? Device access by UUID --------------------- On Linux: /dev/disk/by-uuid/* On FreeBSD and GNU/kFreeBSD: /dev/ufsid/* autofs4 ------- On FreeBSD: 4.4 BSD automounter (amd) On GNU/Hurd: Can be handled natively with translators, for example with the mux translator. binfmt_misc ----------- ?? Peer credentials ================ Sockets ======= Socket length ------------- The BSDs requires some APIs to get the socklen argument be the exact size of the matching sockaddr_AF for that AF. Socket interface names ---------------------- SIOCGIFCONF has some portability issues. Terminals ========= termio vs termios ----------------- The obsolete System V termio interface is based on direct ioctls, portable applications should switch to termios which is defined by POSIX.1-1990. Some systems (like GNU/Hurd) do not even have the termio interface. (in XPG3 and up as XTI extension, but not in Hurd) TABDLY → TBDELAY TAB3 → XTABS (in Hurd but not in XPG3 and up, from BSD) TBDELAY → XTABS → XCASE, OLCUC, IUCLC → [deprecated] VSWTCH → [deprecated] FIOSNBIO → FIONBIO FIONBIO → fctnl(); O_NDELAY ?? CBAUD → cf[sg]et[io]speed(); tcsetattr(); T{IO,}CGET[AS] → tcgetattr(,); T{IO,}CSET[AS] → tcsetattr(,TCSANOW,); T{IO,}CSET[AS]W → tcsetattr(,TCSADRAIN,); T{IO,}CSET[AS]F → tcsetattr(,TCSAFLUSH,); T{IO,}CSBRK → tcdrain(); tcsendbreak(); TCXONC → tcflow(); TCFLSH → tcflush(); TIOCSPGRP → tcsetpgrp() TIOCGPGRP → tcgetpgrp() Note: TC{IO,}C[SG]ETA[ WF] is for termio TC{IO,}C[SG]ETS[ WF] is for termios Signals ======= RT signals ---------- kFreeBSD doesn't support POSIX RT (realtime) signals. We hope that this functionality is added someday but for now it's a porting issue for us. You can detect whether RT signals are available in the system via the SIGRTMIN and SIGRTMAX macros (which are not defined on kfreebsd-gnu). Time ==== time() ------ On BSDs, both and need to be included. System information ================== sysinfo(2) ---------- uptime ------ On Unices: utmpx.ut_tv from utmpx.ut_type == BOOT_TIME. While this is the most portable interface, it has the problem of relying on the utmp file, which might not be available or be valid on early boot situations, or when file systems are RO. The kernel specific interfaces might thus be more reliable. On Linux: sysinfo(2). On BSDs and Darwin: sysctl kern.boottime. On FreeBSD and GNU/kFreeBSD: clock_gettime(CLOCK_UPTIME). On GNU/Hurd, get the task creation time of PID 1 (init): ps_context_find_proc_stat(ctx, 1, &ps); proc_stat_set_flags(ps, PSTAT_TASK_BASIC) proc_stat_task_basic_info(ps)->creation_time; Sizes and limits ================ Portable applications should try not to hardcode size and limits, not only to be future-proof when the limits get raised, but to cope with differences in current systems, either depending on different subsystems or when the limits can change at run-time or on different variations of the same architecture the binary is built for. PAGE_SIZE / PAGESIZE -------------------- Might change at runtime, use sysconf(_SC_PAGESIZE) instead. MAX* ---- Dynamically allocated or sysconf(3). PIPE_BUF ------- pathconf(3) readlink(2) ----------- When reading the symlink contents the most portable and correct way to do it is to retrieve the size of the buffer with lstat(), st_size for the symlink will be the size of the destination buffer. To avoid race conditions and possible truncation one has to use st_size + 1 and verify the readlink() function return size. File Holes ========== On Solaris, FreeBSD and DragonFlyBSD: lseek(SEEK_HOLE/SEEK_DATA) On Linux: FS_IOC_FIEMAP (supported since 2.6.28), FIBMAP (deprecated and requires CAP_ADMIN), lseek(SEEK_HOLE/SEEK_DATA) (supported since 3.1). On NetBSD: lseek(SEEK_HOLE/SEEK_DATA) being worked on Running Process Executable Path =============================== On Linux: readlink(2) /proc/self/exe (only from itself) On FreeBSD: sysctl(2) CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1 readlink(2) /proc/curproc/file (with procfs, only from itself) readlink(2) /proc/self/exe (with linprocfs, only from itself) On DragonFlyBSD: readlink(2) /proc/curproc/file (only from itself) On NetBSD: readlink(2) /proc/curproc/exe (only from itself) On Mac OS X: _NSGetExecutablePath(3) (man dyld) On Solaris: getexecname() (only from itself and dynamically linked execs) Standard I/O ============ STDIO_S_EOF_SEEN No longer in libc 4.5.8 Devices ======= Writing to devfs (kFreeBSD) --------------------------- On kFreeBSD's devfs it's only possible to create block/char devices and symlinks. So if you need to create some thing in /dev, like a named pipe create it in another place, then symlink from /dev. Note that the symlink you put in /dev will be removed on next reboot, so make sure the proper init.d script restores it. Generally, you should use /var/run for your named pipe. The only exception is sysvinit, which can't assume /var is mounted and hence uses /etc. All other daemons can assume /var is mounted, so this shouldn't be an issue. Disk devices (kFreeBSD) ----------------------- On kFreeBSD what usually is a block device on other Unices it's a char device, and as such some operations might not work there.