mirror of
https://github.com/jart/cosmopolitan.git
synced 2024-05-17 02:52:40 +00:00
Improve quality of uname/gethostname/getdomainname
This commit is contained in:
parent
c5c4dfcd21
commit
b66bd064d8
|
@ -12,8 +12,10 @@
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
char hostname[254];
|
char name[254];
|
||||||
CHECK_NE(-1, gethostname(hostname, sizeof(hostname)));
|
CHECK_NE(-1, gethostname(name, sizeof(name)));
|
||||||
puts(hostname);
|
printf("gethostname() → %`'s\n", name);
|
||||||
|
CHECK_NE(-1, getdomainname(name, sizeof(name)));
|
||||||
|
printf("getdomainname() → %`'s\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
struct utsname names;
|
struct utsname names;
|
||||||
if (uname(&names)) return 1;
|
if (uname(&names)) return 1;
|
||||||
printf("%-10s %s\n", "sysname", names.sysname);
|
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", "release", names.release);
|
printf("%-10s %`'s\n", "version", names.version);
|
||||||
printf("%-10s %s\n", "version", names.version);
|
printf("%-10s %`'s\n", "machine", names.machine);
|
||||||
printf("%-10s %s\n", "machine", names.machine);
|
printf("%-10s %`'s\n", "nodename", names.nodename);
|
||||||
printf("%-10s %s\n", "domainname", names.domainname);
|
printf("%-10s %`'s\n", "domainname", names.domainname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
33
libc/calls/getdomainname-linux.c
Normal file
33
libc/calls/getdomainname-linux.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -17,37 +17,65 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/utsname.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/enum/computernameformat.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/str/str.h"
|
||||||
#include "libc/sysv/errfuns.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) {
|
int getdomainname(char *name, size_t len) {
|
||||||
uint32_t nSize;
|
int rc;
|
||||||
struct utsname u;
|
if (len < 0) {
|
||||||
char16_t name16[256];
|
rc = einval();
|
||||||
if (len < 1) return einval();
|
} else if (!len) {
|
||||||
if (!name) return efault();
|
rc = 0;
|
||||||
if (!IsWindows()) {
|
} else if (!name) {
|
||||||
if (uname(&u) == -1) return -1;
|
rc = efault();
|
||||||
if (!memccpy(name, u.domainname[0] ? u.domainname : u.nodename, '\0',
|
} else if (IsLinux()) {
|
||||||
len)) {
|
rc = getdomainname_linux(name, len);
|
||||||
name[len - 1] = '\0';
|
} else if (IsBsd()) {
|
||||||
}
|
rc = gethostname_bsd(name, len, KERN_DOMAINNAME);
|
||||||
return 0;
|
} else if (IsWindows()) {
|
||||||
|
rc = gethostname_nt(name, len, kNtComputerNamePhysicalDnsDomain);
|
||||||
} else {
|
} else {
|
||||||
nSize = ARRAYLEN(name16);
|
rc = enosys();
|
||||||
if (GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) {
|
|
||||||
tprecode16to8(name, len, name16);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return __winerr();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!rc && len && !strcmp(name, "(none)")) {
|
||||||
|
name[0] = 0;
|
||||||
|
}
|
||||||
|
STRACE("getdomainname([%#.*s], %'zu) → %d% m", len, name, len, rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,26 +17,19 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
|
||||||
#define CTL_KERN 1
|
#define CTL_KERN 1
|
||||||
#define KERN_HOSTNAME 10
|
|
||||||
|
|
||||||
int gethostname_bsd(char *name, size_t len) {
|
int gethostname_bsd(char *name, size_t len, int kind) {
|
||||||
char *p;
|
int cmd[2] = {CTL_KERN, kind};
|
||||||
int cmd[2];
|
if (sysctl(cmd, 2, name, &len, 0, 0) != -1) {
|
||||||
char buf[254];
|
return 0;
|
||||||
size_t buflen;
|
} else {
|
||||||
cmd[0] = CTL_KERN;
|
if (errno == ENOMEM) {
|
||||||
cmd[1] = KERN_HOSTNAME;
|
errno = ENAMETOOLONG;
|
||||||
buflen = sizeof(buf);
|
}
|
||||||
if (sysctl(cmd, 2, buf, &buflen, NULL, 0) == -1) {
|
|
||||||
if (errno == ENOMEM) errno = ENAMETOOLONG;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strncpy(name, buf, len);
|
|
||||||
name[len - 1] = '\0';
|
|
||||||
if ((p = strchr(name, '.'))) *p = '\0';
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,19 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/struct/utsname-linux.internal.h"
|
||||||
#include "libc/calls/struct/utsname.h"
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
int gethostname_linux(char *name, size_t len) {
|
int gethostname_linux(char *name, size_t len) {
|
||||||
struct utsname u;
|
struct utsname_linux uts;
|
||||||
if (uname(&u) == -1) return -1;
|
if (!sys_uname_linux(&uts)) {
|
||||||
memccpy(name, u.nodename, '\0', len);
|
if (memccpy(name, uts.nodename, '\0', len)) {
|
||||||
name[len - 1] = '\0';
|
return 0;
|
||||||
return 0;
|
} else {
|
||||||
|
return enametoolong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,22 @@
|
||||||
#include "libc/nt/enum/computernameformat.h"
|
#include "libc/nt/enum/computernameformat.h"
|
||||||
#include "libc/nt/systeminfo.h"
|
#include "libc/nt/systeminfo.h"
|
||||||
#include "libc/str/str.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) {
|
textwindows int gethostname_nt(char *name, size_t len, int kind) {
|
||||||
uint32_t nSize;
|
uint32_t nSize;
|
||||||
|
char name8[256];
|
||||||
char16_t name16[256];
|
char16_t name16[256];
|
||||||
nSize = ARRAYLEN(name16);
|
nSize = ARRAYLEN(name16);
|
||||||
if (GetComputerNameEx(kind, name16, &nSize)) {
|
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;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return __winerr();
|
return __winerr();
|
||||||
|
|
|
@ -17,29 +17,60 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/nt/enum/computernameformat.h"
|
#include "libc/nt/enum/computernameformat.h"
|
||||||
#include "libc/sysv/errfuns.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) {
|
int gethostname(char *name, size_t len) {
|
||||||
if (len < 1) return einval();
|
int rc;
|
||||||
if (!name) return efault();
|
if (len < 0) {
|
||||||
if (!IsWindows()) {
|
rc = einval();
|
||||||
if (!IsBsd()) {
|
} else if (!len) {
|
||||||
return gethostname_linux(name, len);
|
rc = 0;
|
||||||
} else {
|
} else if (!name) {
|
||||||
return gethostname_bsd(name, len);
|
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 {
|
} else {
|
||||||
return gethostname_nt(name, len, kNtComputerNamePhysicalDnsHostname);
|
rc = enosys();
|
||||||
}
|
}
|
||||||
|
STRACE("gethostname([%#.*s], %'zu) → %d% m", len, name, len, rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
19
libc/calls/struct/utsname-linux.internal.h
Normal file
19
libc/calls/struct/utsname-linux.internal.h
Normal file
|
@ -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_ */
|
|
@ -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_ */
|
|
|
@ -7,12 +7,12 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
struct utsname {
|
struct utsname {
|
||||||
char sysname[SYS_NMLN];
|
char sysname[SYS_NMLN]; /* name of os */
|
||||||
char nodename[SYS_NMLN];
|
char nodename[SYS_NMLN]; /* name of network node */
|
||||||
char release[SYS_NMLN];
|
char release[SYS_NMLN]; /* release level */
|
||||||
char version[SYS_NMLN];
|
char version[SYS_NMLN]; /* version level */
|
||||||
char machine[SYS_NMLN];
|
char machine[SYS_NMLN]; /* hardware type */
|
||||||
char domainname[SYS_NMLN];
|
char domainname[SYS_NMLN]; /* domain name */
|
||||||
};
|
};
|
||||||
|
|
||||||
int uname(struct utsname *);
|
int uname(struct utsname *);
|
||||||
|
|
|
@ -7,11 +7,14 @@ COSMOPOLITAN_C_START_
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
bool __is_linux_2_6_23(void) hidden;
|
bool __is_linux_2_6_23(void) hidden;
|
||||||
|
bool32 sys_isatty_metal(int);
|
||||||
int __fixupnewfd(int, int) hidden;
|
int __fixupnewfd(int, int) hidden;
|
||||||
int __notziposat(int, const char *);
|
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_linux(char *, size_t) hidden;
|
||||||
int gethostname_nt(char *, size_t, int) hidden;
|
int gethostname_nt(char *, size_t, int) hidden;
|
||||||
|
int sys_msyscall(void *, size_t);
|
||||||
long sys_bogus(void);
|
long sys_bogus(void);
|
||||||
void *__vdsosym(const char *, const char *) hidden;
|
void *__vdsosym(const char *, const char *) hidden;
|
||||||
void __onfork(void) hidden;
|
void __onfork(void) hidden;
|
||||||
|
@ -19,7 +22,6 @@ void __restore_rt() hidden;
|
||||||
void __restore_rt_netbsd(void) hidden;
|
void __restore_rt_netbsd(void) hidden;
|
||||||
void cosmo2flock(uintptr_t);
|
void cosmo2flock(uintptr_t);
|
||||||
void flock2cosmo(uintptr_t);
|
void flock2cosmo(uintptr_t);
|
||||||
bool32 sys_isatty_metal(int);
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -16,93 +16,171 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/intrin/weaken.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/strace.internal.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/struct/utsname.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.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/calls/syscall_support-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/enum/computernameformat.h"
|
#include "libc/nt/enum/computernameformat.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
#include "libc/nt/struct/teb.h"
|
||||||
|
#include "libc/nt/systeminfo.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/errfuns.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;
|
return NtGetPeb()->OSMajorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline textwindows noasan int NtGetMinorVersion(void) {
|
static inline textwindows noasan int GetNtMinorVersion(void) {
|
||||||
return NtGetPeb()->OSMinorVersion;
|
return NtGetPeb()->OSMinorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline textwindows noasan int NtGetBuildNumber(void) {
|
static inline textwindows noasan int GetNtBuildNumber(void) {
|
||||||
return NtGetPeb()->OSBuildNumber;
|
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
|
* @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;
|
int rc;
|
||||||
char *out, *p;
|
if (!uts || (IsAsan() && !__asan_is_valid(uts, sizeof(*uts)))) {
|
||||||
size_t i, j, len;
|
|
||||||
if (!lool) return efault();
|
|
||||||
if (!lool || (IsAsan() && !__asan_is_valid(lool, sizeof(*lool)))) {
|
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else {
|
} else if (IsLinux()) {
|
||||||
if (!IsWindows()) {
|
struct utsname_linux linux;
|
||||||
if (IsLinux() || IsFreebsd()) {
|
if (!(rc = sys_uname_linux(&linux))) {
|
||||||
char tmp[sizeof(struct utsname)];
|
stpcpy(uts->sysname, linux.sysname);
|
||||||
bzero(tmp, sizeof(tmp));
|
stpcpy(uts->nodename, linux.nodename);
|
||||||
if ((rc = sys_uname(tmp)) != -1) {
|
stpcpy(uts->release, linux.release);
|
||||||
out = (char *)lool;
|
stpcpy(uts->version, linux.version);
|
||||||
for (i = j = 0;;) {
|
stpcpy(uts->machine, linux.machine);
|
||||||
len = strlen(&tmp[j]);
|
stpcpy(uts->domainname, linux.domainname);
|
||||||
if (len >= sizeof(struct utsname) - i) break;
|
if (!strcmp(uts->domainname, "(none)")) {
|
||||||
memcpy(&out[i], &tmp[j], len + 1);
|
uts->domainname[0] = 0;
|
||||||
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 {
|
|
||||||
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,
|
STRACE("uname([{%#s, %#s, %#s, %#s, %#s, %#s}]) → %d% m",
|
||||||
lool->nodename, lool->release, lool->version, lool->machine,
|
Str(rc, uts->sysname), Str(rc, uts->nodename), Str(rc, uts->release),
|
||||||
lool->domainname, rc);
|
Str(rc, uts->version), Str(rc, uts->machine), Str(rc, uts->domainname),
|
||||||
|
rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue