diff --git a/examples/hostname.c b/examples/hostname.c index 998a08cc9..6d076293d 100644 --- a/examples/hostname.c +++ b/examples/hostname.c @@ -12,8 +12,10 @@ #include "libc/stdio/stdio.h" int main(int argc, char *argv[]) { - char hostname[254]; - CHECK_NE(-1, gethostname(hostname, sizeof(hostname))); - puts(hostname); + char name[254]; + CHECK_NE(-1, gethostname(name, sizeof(name))); + printf("gethostname() → %`'s\n", name); + CHECK_NE(-1, getdomainname(name, sizeof(name))); + printf("getdomainname() → %`'s\n", name); return 0; } diff --git a/examples/uname.c b/examples/uname.c index 9cf0c5154..bdaa6cf6b 100644 --- a/examples/uname.c +++ b/examples/uname.c @@ -14,11 +14,11 @@ int main(int argc, char *argv[]) { struct utsname names; if (uname(&names)) return 1; - printf("%-10s %s\n", "sysname", names.sysname); - printf("%-10s %s\n", "nodename", names.nodename); - printf("%-10s %s\n", "release", names.release); - printf("%-10s %s\n", "version", names.version); - printf("%-10s %s\n", "machine", names.machine); - printf("%-10s %s\n", "domainname", names.domainname); + printf("%-10s %`'s\n", "sysname", names.sysname); + printf("%-10s %`'s\n", "release", names.release); + printf("%-10s %`'s\n", "version", names.version); + printf("%-10s %`'s\n", "machine", names.machine); + printf("%-10s %`'s\n", "nodename", names.nodename); + printf("%-10s %`'s\n", "domainname", names.domainname); return 0; } diff --git a/libc/calls/getdomainname-linux.c b/libc/calls/getdomainname-linux.c new file mode 100644 index 000000000..120a91bee --- /dev/null +++ b/libc/calls/getdomainname-linux.c @@ -0,0 +1,33 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/utsname-linux.internal.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +int getdomainname_linux(char *name, size_t len) { + struct utsname_linux uts; + if (!sys_uname_linux(&uts)) { + if (memccpy(name, uts.domainname, '\0', len)) { + return 0; + } else { + return enametoolong(); + } + } + return -1; +} diff --git a/libc/calls/getdomainname.c b/libc/calls/getdomainname.c index 691d08b7d..aa2c7e854 100644 --- a/libc/calls/getdomainname.c +++ b/libc/calls/getdomainname.c @@ -17,37 +17,65 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/struct/utsname.h" -#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/nt/enum/computernameformat.h" -#include "libc/nt/errors.h" -#include "libc/nt/runtime.h" -#include "libc/nt/systeminfo.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" +#define KERN_DOMAINNAME 22 + +/** + * Returns domain of current host. + * + * For example, if the fully-qualified hostname is "host.domain.example" + * then this SHOULD return "domain.example" however, it might not be the + * case; it depends on how the host machine is configured. + * + * The nul / mutation semantics are tricky. Here is some safe copypasta: + * + * char domain[254]; + * if (getdomainname(domain, sizeof(domain))) { + * strcpy(domain, "(none)"); + * } + * + * On Linux this is the same as `/proc/sys/kernel/domainname`. However, + * we turn the weird `"(none)"` string into empty string. + * + * @param name receives output name, which is guaranteed to be complete + * and have a nul-terminator if this function return zero + * @param len is size of `name` consider using `DNS_NAME_MAX + 1` (254) + * @raise EINVAL if `len` is negative + * @raise EFAULT if `name` is an invalid address + * @raise ENAMETOOLONG if the underlying system call succeeded, but the + * returned hostname had a length equal to or greater than `len` in + * which case this error is raised and the buffer is modified, with + * as many bytes of hostname as possible excluding a nul-terminator + * @return 0 on success, or -1 w/ errno + */ int getdomainname(char *name, size_t len) { - uint32_t nSize; - struct utsname u; - char16_t name16[256]; - if (len < 1) return einval(); - if (!name) return efault(); - if (!IsWindows()) { - if (uname(&u) == -1) return -1; - if (!memccpy(name, u.domainname[0] ? u.domainname : u.nodename, '\0', - len)) { - name[len - 1] = '\0'; - } - return 0; + int rc; + if (len < 0) { + rc = einval(); + } else if (!len) { + rc = 0; + } else if (!name) { + rc = efault(); + } else if (IsLinux()) { + rc = getdomainname_linux(name, len); + } else if (IsBsd()) { + rc = gethostname_bsd(name, len, KERN_DOMAINNAME); + } else if (IsWindows()) { + rc = gethostname_nt(name, len, kNtComputerNamePhysicalDnsDomain); } else { - nSize = ARRAYLEN(name16); - if (GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) { - tprecode16to8(name, len, name16); - return 0; - } else { - return __winerr(); - } + rc = enosys(); } + if (!rc && len && !strcmp(name, "(none)")) { + name[0] = 0; + } + STRACE("getdomainname([%#.*s], %'zu) → %d% m", len, name, len, rc); + return rc; } diff --git a/libc/calls/gethostname-bsd.c b/libc/calls/gethostname-bsd.c index 23d5317c8..9b3d4d57d 100644 --- a/libc/calls/gethostname-bsd.c +++ b/libc/calls/gethostname-bsd.c @@ -17,26 +17,19 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/errno.h" -#include "libc/str/str.h" -#define CTL_KERN 1 -#define KERN_HOSTNAME 10 +#define CTL_KERN 1 -int gethostname_bsd(char *name, size_t len) { - char *p; - int cmd[2]; - char buf[254]; - size_t buflen; - cmd[0] = CTL_KERN; - cmd[1] = KERN_HOSTNAME; - buflen = sizeof(buf); - if (sysctl(cmd, 2, buf, &buflen, NULL, 0) == -1) { - if (errno == ENOMEM) errno = ENAMETOOLONG; +int gethostname_bsd(char *name, size_t len, int kind) { + int cmd[2] = {CTL_KERN, kind}; + if (sysctl(cmd, 2, name, &len, 0, 0) != -1) { + return 0; + } else { + if (errno == ENOMEM) { + errno = ENAMETOOLONG; + } return -1; } - strncpy(name, buf, len); - name[len - 1] = '\0'; - if ((p = strchr(name, '.'))) *p = '\0'; - return 0; } diff --git a/libc/calls/gethostname-linux.c b/libc/calls/gethostname-linux.c index 979cfb6e2..f92edac32 100644 --- a/libc/calls/gethostname-linux.c +++ b/libc/calls/gethostname-linux.c @@ -16,15 +16,19 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/calls/struct/utsname.h" +#include "libc/calls/struct/utsname-linux.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" int gethostname_linux(char *name, size_t len) { - struct utsname u; - if (uname(&u) == -1) return -1; - memccpy(name, u.nodename, '\0', len); - name[len - 1] = '\0'; - return 0; + struct utsname_linux uts; + if (!sys_uname_linux(&uts)) { + if (memccpy(name, uts.nodename, '\0', len)) { + return 0; + } else { + return enametoolong(); + } + } + return -1; } diff --git a/libc/calls/gethostname-nt.c b/libc/calls/gethostname-nt.c index 906d29980..2f0cb5cf5 100644 --- a/libc/calls/gethostname-nt.c +++ b/libc/calls/gethostname-nt.c @@ -22,13 +22,22 @@ #include "libc/nt/enum/computernameformat.h" #include "libc/nt/systeminfo.h" #include "libc/str/str.h" +#include "libc/sysv/errfuns.h" +// Guarantees NUL-terminator, if zero is returned. +// Mutates on ENAMETOOLONG without nul-terminator. textwindows int gethostname_nt(char *name, size_t len, int kind) { uint32_t nSize; + char name8[256]; char16_t name16[256]; nSize = ARRAYLEN(name16); if (GetComputerNameEx(kind, name16, &nSize)) { - tprecode16to8(name, len, name16); + tprecode16to8(name8, sizeof(name8), name16); + if (memccpy(name, name8, '\0', len)) { + return 0; + } else { + return enametoolong(); + } return 0; } else { return __winerr(); diff --git a/libc/calls/gethostname.c b/libc/calls/gethostname.c index 743525483..ffd5ac6df 100644 --- a/libc/calls/gethostname.c +++ b/libc/calls/gethostname.c @@ -17,29 +17,60 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/nt/enum/computernameformat.h" #include "libc/sysv/errfuns.h" +#define KERN_HOSTNAME 10 + /** - * Returns name of host system, e.g. + * Returns name of current host. * - * pheidippides.domain.example - * ^^^^^^^^^^^^ + * For example, if the fully-qualified hostname is "host.domain.example" + * then this SHOULD return "host" however that might not be the case; it + * depends on how the host machine is configured. It's fair to say if it + * has a dot, it's a FQDN, otherwise it's a node. * - * @return 0 on success or -1 w/ errno + * The nul / mutation semantics are tricky. Here is some safe copypasta: + * + * char host[254]; + * if (gethostname(host, sizeof(host))) { + * strcpy(host, "localhost"); + * } + * + * On Linux this is the same as `/proc/sys/kernel/hostname`. + * + * @param name receives output name, which is guaranteed to be complete + * and have a nul-terminator if this function return zero + * @param len is size of `name` consider using `DNS_NAME_MAX + 1` (254) + * @raise EINVAL if `len` is negative + * @raise EFAULT if `name` is an invalid address + * @raise ENAMETOOLONG if the underlying system call succeeded, but the + * returned hostname had a length equal to or greater than `len` in + * which case this error is raised and the buffer is modified, with + * as many bytes of hostname as possible excluding a nul-terminator + * @return 0 on success, or -1 w/ errno */ int gethostname(char *name, size_t len) { - if (len < 1) return einval(); - if (!name) return efault(); - if (!IsWindows()) { - if (!IsBsd()) { - return gethostname_linux(name, len); - } else { - return gethostname_bsd(name, len); - } + int rc; + if (len < 0) { + rc = einval(); + } else if (!len) { + rc = 0; + } else if (!name) { + rc = efault(); + } else if (IsLinux()) { + rc = gethostname_linux(name, len); + } else if (IsBsd()) { + rc = gethostname_bsd(name, len, KERN_HOSTNAME); + } else if (IsWindows()) { + rc = gethostname_nt(name, len, kNtComputerNamePhysicalDnsHostname); } else { - return gethostname_nt(name, len, kNtComputerNamePhysicalDnsHostname); + rc = enosys(); } + STRACE("gethostname([%#.*s], %'zu) → %d% m", len, name, len, rc); + return rc; } diff --git a/libc/calls/struct/utsname-linux.internal.h b/libc/calls/struct/utsname-linux.internal.h new file mode 100644 index 000000000..3d8dd04a4 --- /dev/null +++ b/libc/calls/struct/utsname-linux.internal.h @@ -0,0 +1,19 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct utsname_linux { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +int sys_uname_linux(struct utsname_linux *) asm("sys_uname"); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_ */ diff --git a/libc/calls/struct/utsname-netbsd.internal.h b/libc/calls/struct/utsname-netbsd.internal.h deleted file mode 100644 index 811f79c18..000000000 --- a/libc/calls/struct/utsname-netbsd.internal.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_NETBSD_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_NETBSD_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct utsname_netbsd { - char sysname[256]; /* name of os */ - char nodename[256]; /* name of network node */ - char release[256]; /* release level */ - char version[256]; /* version level */ - char machine[256]; /* hardware type */ -}; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_NETBSD_INTERNAL_H_ */ diff --git a/libc/calls/struct/utsname.h b/libc/calls/struct/utsname.h index 2ca96a1c9..92d5b0713 100644 --- a/libc/calls/struct/utsname.h +++ b/libc/calls/struct/utsname.h @@ -7,12 +7,12 @@ COSMOPOLITAN_C_START_ struct utsname { - char sysname[SYS_NMLN]; - char nodename[SYS_NMLN]; - char release[SYS_NMLN]; - char version[SYS_NMLN]; - char machine[SYS_NMLN]; - char domainname[SYS_NMLN]; + char sysname[SYS_NMLN]; /* name of os */ + char nodename[SYS_NMLN]; /* name of network node */ + char release[SYS_NMLN]; /* release level */ + char version[SYS_NMLN]; /* version level */ + char machine[SYS_NMLN]; /* hardware type */ + char domainname[SYS_NMLN]; /* domain name */ }; int uname(struct utsname *); diff --git a/libc/calls/syscall_support-sysv.internal.h b/libc/calls/syscall_support-sysv.internal.h index bc6a023ae..8b2b41f68 100644 --- a/libc/calls/syscall_support-sysv.internal.h +++ b/libc/calls/syscall_support-sysv.internal.h @@ -7,11 +7,14 @@ COSMOPOLITAN_C_START_ ╚────────────────────────────────────────────────────────────────────────────│*/ bool __is_linux_2_6_23(void) hidden; +bool32 sys_isatty_metal(int); int __fixupnewfd(int, int) hidden; int __notziposat(int, const char *); -int gethostname_bsd(char *, size_t) hidden; +int getdomainname_linux(char *, size_t) hidden; +int gethostname_bsd(char *, size_t, int) hidden; int gethostname_linux(char *, size_t) hidden; int gethostname_nt(char *, size_t, int) hidden; +int sys_msyscall(void *, size_t); long sys_bogus(void); void *__vdsosym(const char *, const char *) hidden; void __onfork(void) hidden; @@ -19,7 +22,6 @@ void __restore_rt() hidden; void __restore_rt_netbsd(void) hidden; void cosmo2flock(uintptr_t); void flock2cosmo(uintptr_t); -bool32 sys_isatty_metal(int); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/uname.c b/libc/calls/uname.c index f7686770c..e4e5d3660 100644 --- a/libc/calls/uname.c +++ b/libc/calls/uname.c @@ -16,93 +16,171 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/strace.internal.h" -#include "libc/calls/struct/utsname-netbsd.internal.h" +#include "libc/calls/struct/utsname-linux.internal.h" #include "libc/calls/struct/utsname.h" #include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" +#include "libc/errno.h" #include "libc/fmt/itoa.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/weaken.h" #include "libc/log/log.h" +#include "libc/macros.internal.h" #include "libc/nt/enum/computernameformat.h" #include "libc/nt/struct/teb.h" +#include "libc/nt/systeminfo.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" -static inline textwindows noasan int NtGetMajorVersion(void) { +#define CTL_KERN 1 +#define KERN_OSTYPE 1 +#define KERN_OSRELEASE 2 +#define KERN_VERSION 4 +#define KERN_HOSTNAME 10 +#define KERN_DOMAINNAME 22 + +#define CTL_HW 6 +#define HW_MACHINE 1 + +// Gets BSD sysctl() string, guaranteeing NUL-terminator. +// We ignore errors since this syscall mutates on ENOMEM. +// In that case, sysctl() doesn't guarantee the nul term. +static void GetBsdStr(int c0, int c1, char *s) { + char *p; + int e = errno; + size_t n = SYS_NMLN; + int cmd[2] = {c0, c1}; + bzero(s, n), --n; + sysctl(cmd, 2, s, &n, NULL, 0); + errno = e; + // sysctl kern.version is too verbose for uname + if ((p = strchr(s, '\n'))) { + *p = 0; + } +} + +// Gets NT name ignoring errors with guaranteed NUL-terminator. +static textwindows void GetNtName(char *name, int kind) { + uint32_t n = SYS_NMLN; + char16_t name16[256]; + uint32_t size = ARRAYLEN(name16); + if (GetComputerNameEx(kind, name16, &size)) { + tprecode16to8(name, SYS_NMLN, name16); + } else { + name[0] = 0; + } +} + +static inline textwindows noasan int GetNtMajorVersion(void) { return NtGetPeb()->OSMajorVersion; } -static inline textwindows noasan int NtGetMinorVersion(void) { +static inline textwindows noasan int GetNtMinorVersion(void) { return NtGetPeb()->OSMinorVersion; } -static inline textwindows noasan int NtGetBuildNumber(void) { +static inline textwindows noasan int GetNtBuildNumber(void) { return NtGetPeb()->OSBuildNumber; } +static textwindows void GetNtVersion(char *p) { + p = FormatUint32(p, GetNtMajorVersion()), *p++ = '.'; + p = FormatUint32(p, GetNtMinorVersion()), *p++ = '-'; + p = FormatUint32(p, GetNtBuildNumber()); +} + +static const char *Str(int rc, const char *s) { + return !rc ? s : "n/a"; +} + /** - * Asks kernel to give us the `uname -a` data. + * Asks kernel to give us `uname -a` data. + * + * - `machine` should be one of: + * + * - `x86_64` + * - `amd64` + * + * - `sysname` should be one of: + * + * - `Linux` + * - `FreeBSD` + * - `NetBSD` + * - `OpenBSD` + * - `Darwin` + * - `Windows` + * + * - `version` contains the distro name, version, and release date. On + * FreeBSD/NetBSD/OpenBSD this may contain newline characters, which + * this polyfill hides by setting the first newline character to nul + * although the information can be restored by putting newline back. + * BSDs usually repeat the `sysname` and `release` in the `version`. + * + * - `nodename` *may* be the first label of the fully qualified hostname + * of the current host. This is equivalent to gethostname(), except we + * guarantee a NUL-terminator here with truncation, which should never + * happen unless the machine violates the DNS standard. If it has dots + * then it's fair to assume it's an FQDN. On Linux this is the same as + * the content of `/proc/sys/kernel/hostname`. + * + * - `domainname` *may* be the higher-order labels of the FQDN for this + * host. This is equivalent to getdomainname(), except we guarantee a + * NUL-terminator here with truncation, which should never happen w/o + * violating the DNS standard. If this field is not present, it'll be + * coerced to empty string. On Linux, this is the same as the content + * of `/proc/sys/kernel/domainname`. + * + * The returned fields are guaranteed to be nul-terminated. + * * @return 0 on success, or -1 w/ errno + * @raise EFAULT if `buf` isn't valid + * @raise ENOSYS on metal */ -int uname(struct utsname *lool) { +int uname(struct utsname *uts) { int rc; - char *out, *p; - size_t i, j, len; - if (!lool) return efault(); - if (!lool || (IsAsan() && !__asan_is_valid(lool, sizeof(*lool)))) { + if (!uts || (IsAsan() && !__asan_is_valid(uts, sizeof(*uts)))) { rc = efault(); - } else { - if (!IsWindows()) { - if (IsLinux() || IsFreebsd()) { - char tmp[sizeof(struct utsname)]; - bzero(tmp, sizeof(tmp)); - if ((rc = sys_uname(tmp)) != -1) { - out = (char *)lool; - for (i = j = 0;;) { - len = strlen(&tmp[j]); - if (len >= sizeof(struct utsname) - i) break; - memcpy(&out[i], &tmp[j], len + 1); - i += SYS_NMLN; - j += len; - while (j < sizeof(tmp) && tmp[j] == '\0') ++j; - if (j == sizeof(tmp)) break; - } - } - } else if (IsXnu()) { - strcpy(lool->sysname, "XNU's Not UNIX!"); - gethostname_bsd(lool->nodename, sizeof(lool->nodename)); - rc = 0; - } else if (IsOpenbsd()) { - strcpy(lool->sysname, "OpenBSD"); - gethostname_bsd(lool->nodename, sizeof(lool->nodename)); - rc = 0; - } else if (IsNetbsd()) { - strcpy(lool->sysname, "NetBSD"); - gethostname_bsd(lool->nodename, sizeof(lool->nodename)); - rc = 0; - } else { - rc = enosys(); + } else if (IsLinux()) { + struct utsname_linux linux; + if (!(rc = sys_uname_linux(&linux))) { + stpcpy(uts->sysname, linux.sysname); + stpcpy(uts->nodename, linux.nodename); + stpcpy(uts->release, linux.release); + stpcpy(uts->version, linux.version); + stpcpy(uts->machine, linux.machine); + stpcpy(uts->domainname, linux.domainname); + if (!strcmp(uts->domainname, "(none)")) { + uts->domainname[0] = 0; } - } else { - p = lool->release; - p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.'; - p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-'; - p = FormatUint32(p, NtGetBuildNumber()); - strcpy(lool->sysname, "The New Technology"); - strcpy(lool->machine, "x86_64"); - rc = gethostname_nt(lool->nodename, sizeof(lool->nodename), - kNtComputerNamePhysicalDnsHostname); - rc |= gethostname_nt(lool->domainname, sizeof(lool->domainname), - kNtComputerNamePhysicalDnsDomain); } + } else if (IsBsd()) { + GetBsdStr(CTL_KERN, KERN_OSTYPE, uts->sysname); + GetBsdStr(CTL_KERN, KERN_HOSTNAME, uts->nodename); + GetBsdStr(CTL_KERN, KERN_DOMAINNAME, uts->domainname); + GetBsdStr(CTL_KERN, KERN_OSRELEASE, uts->release); + GetBsdStr(CTL_KERN, KERN_VERSION, uts->version); + GetBsdStr(CTL_HW, HW_MACHINE, uts->machine); + rc = 0; + } else if (IsWindows()) { + stpcpy(uts->sysname, "Windows"); + stpcpy(uts->machine, "x86_64"); + GetNtVersion(stpcpy(uts->version, "Windows ")); + GetNtVersion(uts->release); + GetNtName(uts->nodename, kNtComputerNamePhysicalDnsHostname); + GetNtName(uts->domainname, kNtComputerNamePhysicalDnsDomain); + rc = 0; + } else { + rc = enosys(); } - STRACE("uname([%s, %s, %s, %s, %s, %s]) → %d% m", lool->sysname, - lool->nodename, lool->release, lool->version, lool->machine, - lool->domainname, rc); + STRACE("uname([{%#s, %#s, %#s, %#s, %#s, %#s}]) → %d% m", + Str(rc, uts->sysname), Str(rc, uts->nodename), Str(rc, uts->release), + Str(rc, uts->version), Str(rc, uts->machine), Str(rc, uts->domainname), + rc); return rc; }