Raw bindings to Linux platform APIs for .NET Core.
The APIs provided by this package stay as close as possible to the native declarations. Because the native APIs are different per platform (e.g. linux-arm64 vs linux-x64), the package contains separate assemblies for each platform.
.NET Core will use the appropriate assembly based on the rid.
- linux x64 glibc
- linux arm64 glibc
- linux arm32 glibc
Add the package using the dotnet
cli:
$ dotnet add package Tmds.LibC
Alternatively, you can use a daily build from the https://www.myget.org/F/tmds/api/v3/index.json NuGet feed.
Program.cs
using System;
using System.Text;
using Tmds.Linux;
using static Tmds.Linux.LibC;
namespace console
{
class Program
{
unsafe static void Main(string[] args)
{
var bytes = Encoding.UTF8.GetBytes("Hello world!");
fixed (byte* buffer = bytes)
{
write(STDOUT_FILENO, buffer, bytes.Length);
}
}
}
}
The following functions are defined in the static class Tmds.Linux.LibC
:
_exit, accept, accept4, access, acct, alarm, bind, brk, cfgetispeed, cfgetospeed, cfsetispeed, cfsetospeed, chdir, chmod, chown, chroot, clone, close, confstr, connect, creat, ctermid, daemon, dladdr, dlclose, dlerror, dlinfo, dlopen, dlsym, dlvsym, dup, dup2, dup3, eaccess, epoll_create, epoll_create1, epoll_ctl, epoll_pwait, epoll_wait, euidaccess, eventfd, execve, faccessat, fallocate, fchdir, fchmod, fchmodat, fchown, fchownat, fcntl, fdatasync, fexecve, fork, fpathconf, fstat, fstatat, fstatvfs, fsync, ftruncate, futimens, getcwd, getdomainname, getdtablesize, getegid, geteuid, getgid, getgrnam_r, getgroups, gethostid, gethostname, getlogin, getlogin_r, getpagesize, getpeername, getpgid, getpgrp, getpid, getppid, getresgid, getresuid, getsid, getsockname, getsockopt, getuid, htons, io_destroy, io_getevents, io_setup, io_submit, io_uring_enter, io_uring_register, io_uring_setup, ioctl, isatty, kill, killpg, lchown, link, linkat, listen, lockf, lseek, lstat, madvise, memfd_create, mincore, mkdir, mkdirat, mkfifo, mkfifoat, mknod, mknodat, mlock, mlock2, mlockall, mmap, mount, mprotect, mremap, msync, munlock, munlockall, munmap, name_to_handle_at, nice, ntohs, open, open_by_handle_at, openat, openat2, pathconf, pause, pipe, pipe2, poll, posix_fadvise, posix_fallocate, ppoll, pread, psiginfo, psignal, pthread_kill, pthread_sigmask, pwrite, raise, read, readahead, readlink, readlinkat, recv, recvfrom, recvmmsg, recvmsg, remap_file_pages, rmdir, sbrk, sched_get_priority_max, sched_get_priority_min, sched_getaffinity, sched_getcpu, sched_getscheduler, sched_rr_get_interval, sched_setaffinity, sched_yield, send, sendmmsg, sendmsg, sendto, setdomainname, setegid, seteuid, setgid, setgroups, sethostname, setns, setpgid, setpgrp, setregid, setresgid, setresuid, setreuid, setsid, setsockopt, setuid, shutdown, sigaction, sigaddset, sigaltstack, sigandset, sigdelset, sigemptyset, sigfillset, sighold, sigignore, siginterrupt, sigisemptyset, sigismember, sigorset, sigpause, sigpending, sigprocmask, sigqueue, sigrelse, sigsuspend, sigtimedwait, sigwait, sigwaitinfo, sleep, socket, socketpair, splice, stat, statvfs, statx, strerror_r, symlink, symlinkat, sync, sync_file_range, syncfs, syscall, sysconf, tcdrain, tcflow, tcflush, tcgetattr, tcgetpgrp, tcgetsid, tcsendbreak, tcsetattr, tcsetpgrp, tee, truncate, ttyname, ttyname_r, ualarm, umask, umount, umount2, unlink, unlinkat, unshare, usleep, utimensat, vfork, vhangup, vmsplice, write,
The following structs are defined in the Tmds.Linux
namespace:
aio_context_t, aio_ring, blkcnt_t, blksize_t, clock_t, cmsghdr, cpu_set_t, dev_t, Dl_info, epoll_data_t, epoll_event, f_owner_ex, file_handle, flock, fsblkcnt_t, fsfilcnt_t, gid_t, group, group_filter, group_req, group_source_req, in_addr, in_pktinfo, in6_addr, in6_pktinfo, ino_t, io_cqring_offsets, io_event, io_sqring_offsets, io_uring_cqe, io_uring_files_update, io_uring_params, io_uring_probe, io_uring_probe_op, io_uring_sqe, iocb, iovec, ip_mreq, ip_mreq_source, ip_mreqn, ip_opts, ip6_mtuinfo, ipv6_mreq, linger, long_t, mmsghdr, mode_t, msghdr, nlink_t, off_t, open_how, packet_mreq, pid_t, pollfd, pthread_t, sa_family_t, scm_timestamping, sigaction, sigevent_t, siginfo_t, sigset_t, sigval, size_t, sock_extended_err, sockaddr, sockaddr_hci, sockaddr_in, sockaddr_in6, sockaddr_l2, sockaddr_ll, sockaddr_storage, sockaddr_un, socklen_t, ssize_t, stack_t, stat, statvfs, statx, statx_timestamp, syscall_arg, termios, time_t, timespec, ucred, uid_t, ulong_t, winsize,
This section shows some examples. The examples use a PlatformException
class which is implemented as follows:
class PlatformException : Exception
{
public PlatformException(int errno) :
base(GetErrorMessage(errno))
{
HResult = errno;
}
public PlatformException() :
this(LibC.errno)
{}
private unsafe static string GetErrorMessage(int errno)
{
int bufferLength = 1024;
byte* buffer = stackalloc byte[bufferLength];
int rv = strerror_r(errno, buffer, bufferLength);
return rv == 0 ? Marshal.PtrToStringAnsi((IntPtr)buffer) : $"errno {errno}";
}
public static void Throw() => throw new PlatformException();
}
static class SocketExtensions
{
public static unsafe void SetRawSocketOption(this Socket socket, int level, int optname, int optval)
{
SafeHandle handle = socket.SafeHandle;
bool refAdded = false;
try
{
handle.DangerousAddRef(ref refAdded);
int rv = setsockopt(handle.DangerousGetHandle().ToInt32(), level, optname, &optval, sizeof(int));
if (rv != 0)
{
PlatformException.Throw();
}
}
finally
{
if (refAdded)
handle.DangerousRelease();
}
}
}
This extension method can be used with the constants provided by Tmds.LibC
, for example:
socket.SetRawSocketOption(SOL_SOCKET, SO_REUSEADDR, 1);
Unix processes can be requested to terminate using the SIGTERM
signal. The following code adds an extension
method to the Process
class to send that signal.
static class ProcessExtensions
{
public static void Terminate(this Process process)
{
if (process.HasExited)
{
return;
}
int rv = kill(process.Handle.ToInt32(), SIGTERM);
if (rv == -1 &&
errno != ESRCH /* process does not exist, assume it exited */)
{
PlatformException.Throw();
}
}
}
static class FileUtils
{
public unsafe static string CreatePrivateTempDirectory()
{
string path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
int byteLength = Encoding.UTF8.GetByteCount(path) + 1;
Span<byte> bytes = byteLength <= 128 ? stackalloc byte[byteLength] : new byte[byteLength];
Encoding.UTF8.GetBytes(path, bytes);
fixed (byte* pathname = bytes)
{
int rv = mkdir(pathname, S_IRWXU);
if (rv == -1)
{
PlatformException.Throw();
}
}
return path;
}
}