Skip to content

Commit b66bd06

Browse files
committed
Improve quality of uname/gethostname/getdomainname
1 parent c5c4dfc commit b66bd06

13 files changed

+334
-151
lines changed

examples/hostname.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
#include "libc/stdio/stdio.h"
1313

1414
int main(int argc, char *argv[]) {
15-
char hostname[254];
16-
CHECK_NE(-1, gethostname(hostname, sizeof(hostname)));
17-
puts(hostname);
15+
char name[254];
16+
CHECK_NE(-1, gethostname(name, sizeof(name)));
17+
printf("gethostname() → %`'s\n", name);
18+
CHECK_NE(-1, getdomainname(name, sizeof(name)));
19+
printf("getdomainname() → %`'s\n", name);
1820
return 0;
1921
}

examples/uname.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
int main(int argc, char *argv[]) {
1515
struct utsname names;
1616
if (uname(&names)) return 1;
17-
printf("%-10s %s\n", "sysname", names.sysname);
18-
printf("%-10s %s\n", "nodename", names.nodename);
19-
printf("%-10s %s\n", "release", names.release);
20-
printf("%-10s %s\n", "version", names.version);
21-
printf("%-10s %s\n", "machine", names.machine);
22-
printf("%-10s %s\n", "domainname", names.domainname);
17+
printf("%-10s %`'s\n", "sysname", names.sysname);
18+
printf("%-10s %`'s\n", "release", names.release);
19+
printf("%-10s %`'s\n", "version", names.version);
20+
printf("%-10s %`'s\n", "machine", names.machine);
21+
printf("%-10s %`'s\n", "nodename", names.nodename);
22+
printf("%-10s %`'s\n", "domainname", names.domainname);
2323
return 0;
2424
}

libc/calls/getdomainname-linux.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2020 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/calls/struct/utsname-linux.internal.h"
20+
#include "libc/str/str.h"
21+
#include "libc/sysv/errfuns.h"
22+
23+
int getdomainname_linux(char *name, size_t len) {
24+
struct utsname_linux uts;
25+
if (!sys_uname_linux(&uts)) {
26+
if (memccpy(name, uts.domainname, '\0', len)) {
27+
return 0;
28+
} else {
29+
return enametoolong();
30+
}
31+
}
32+
return -1;
33+
}

libc/calls/getdomainname.c

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,65 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20-
#include "libc/calls/struct/utsname.h"
21-
#include "libc/calls/syscall_support-nt.internal.h"
20+
#include "libc/calls/strace.internal.h"
21+
#include "libc/calls/syscall_support-sysv.internal.h"
2222
#include "libc/dce.h"
23+
#include "libc/intrin/kprintf.h"
2324
#include "libc/macros.internal.h"
2425
#include "libc/nt/enum/computernameformat.h"
25-
#include "libc/nt/errors.h"
26-
#include "libc/nt/runtime.h"
27-
#include "libc/nt/systeminfo.h"
2826
#include "libc/str/str.h"
2927
#include "libc/sysv/errfuns.h"
3028

29+
#define KERN_DOMAINNAME 22
30+
31+
/**
32+
* Returns domain of current host.
33+
*
34+
* For example, if the fully-qualified hostname is "host.domain.example"
35+
* then this SHOULD return "domain.example" however, it might not be the
36+
* case; it depends on how the host machine is configured.
37+
*
38+
* The nul / mutation semantics are tricky. Here is some safe copypasta:
39+
*
40+
* char domain[254];
41+
* if (getdomainname(domain, sizeof(domain))) {
42+
* strcpy(domain, "(none)");
43+
* }
44+
*
45+
* On Linux this is the same as `/proc/sys/kernel/domainname`. However,
46+
* we turn the weird `"(none)"` string into empty string.
47+
*
48+
* @param name receives output name, which is guaranteed to be complete
49+
* and have a nul-terminator if this function return zero
50+
* @param len is size of `name` consider using `DNS_NAME_MAX + 1` (254)
51+
* @raise EINVAL if `len` is negative
52+
* @raise EFAULT if `name` is an invalid address
53+
* @raise ENAMETOOLONG if the underlying system call succeeded, but the
54+
* returned hostname had a length equal to or greater than `len` in
55+
* which case this error is raised and the buffer is modified, with
56+
* as many bytes of hostname as possible excluding a nul-terminator
57+
* @return 0 on success, or -1 w/ errno
58+
*/
3159
int getdomainname(char *name, size_t len) {
32-
uint32_t nSize;
33-
struct utsname u;
34-
char16_t name16[256];
35-
if (len < 1) return einval();
36-
if (!name) return efault();
37-
if (!IsWindows()) {
38-
if (uname(&u) == -1) return -1;
39-
if (!memccpy(name, u.domainname[0] ? u.domainname : u.nodename, '\0',
40-
len)) {
41-
name[len - 1] = '\0';
42-
}
43-
return 0;
60+
int rc;
61+
if (len < 0) {
62+
rc = einval();
63+
} else if (!len) {
64+
rc = 0;
65+
} else if (!name) {
66+
rc = efault();
67+
} else if (IsLinux()) {
68+
rc = getdomainname_linux(name, len);
69+
} else if (IsBsd()) {
70+
rc = gethostname_bsd(name, len, KERN_DOMAINNAME);
71+
} else if (IsWindows()) {
72+
rc = gethostname_nt(name, len, kNtComputerNamePhysicalDnsDomain);
4473
} else {
45-
nSize = ARRAYLEN(name16);
46-
if (GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) {
47-
tprecode16to8(name, len, name16);
48-
return 0;
49-
} else {
50-
return __winerr();
51-
}
74+
rc = enosys();
75+
}
76+
if (!rc && len && !strcmp(name, "(none)")) {
77+
name[0] = 0;
5278
}
79+
STRACE("getdomainname([%#.*s], %'zu) → %d% m", len, name, len, rc);
80+
return rc;
5381
}

libc/calls/gethostname-bsd.c

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,19 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20+
#include "libc/calls/syscall_support-sysv.internal.h"
2021
#include "libc/errno.h"
21-
#include "libc/str/str.h"
2222

23-
#define CTL_KERN 1
24-
#define KERN_HOSTNAME 10
23+
#define CTL_KERN 1
2524

26-
int gethostname_bsd(char *name, size_t len) {
27-
char *p;
28-
int cmd[2];
29-
char buf[254];
30-
size_t buflen;
31-
cmd[0] = CTL_KERN;
32-
cmd[1] = KERN_HOSTNAME;
33-
buflen = sizeof(buf);
34-
if (sysctl(cmd, 2, buf, &buflen, NULL, 0) == -1) {
35-
if (errno == ENOMEM) errno = ENAMETOOLONG;
25+
int gethostname_bsd(char *name, size_t len, int kind) {
26+
int cmd[2] = {CTL_KERN, kind};
27+
if (sysctl(cmd, 2, name, &len, 0, 0) != -1) {
28+
return 0;
29+
} else {
30+
if (errno == ENOMEM) {
31+
errno = ENAMETOOLONG;
32+
}
3633
return -1;
3734
}
38-
strncpy(name, buf, len);
39-
name[len - 1] = '\0';
40-
if ((p = strchr(name, '.'))) *p = '\0';
41-
return 0;
4235
}

libc/calls/gethostname-linux.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19-
#include "libc/calls/calls.h"
20-
#include "libc/calls/struct/utsname.h"
19+
#include "libc/calls/struct/utsname-linux.internal.h"
20+
#include "libc/calls/syscall_support-sysv.internal.h"
2121
#include "libc/str/str.h"
2222
#include "libc/sysv/errfuns.h"
2323

2424
int gethostname_linux(char *name, size_t len) {
25-
struct utsname u;
26-
if (uname(&u) == -1) return -1;
27-
memccpy(name, u.nodename, '\0', len);
28-
name[len - 1] = '\0';
29-
return 0;
25+
struct utsname_linux uts;
26+
if (!sys_uname_linux(&uts)) {
27+
if (memccpy(name, uts.nodename, '\0', len)) {
28+
return 0;
29+
} else {
30+
return enametoolong();
31+
}
32+
}
33+
return -1;
3034
}

libc/calls/gethostname-nt.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,22 @@
2222
#include "libc/nt/enum/computernameformat.h"
2323
#include "libc/nt/systeminfo.h"
2424
#include "libc/str/str.h"
25+
#include "libc/sysv/errfuns.h"
2526

27+
// Guarantees NUL-terminator, if zero is returned.
28+
// Mutates on ENAMETOOLONG without nul-terminator.
2629
textwindows int gethostname_nt(char *name, size_t len, int kind) {
2730
uint32_t nSize;
31+
char name8[256];
2832
char16_t name16[256];
2933
nSize = ARRAYLEN(name16);
3034
if (GetComputerNameEx(kind, name16, &nSize)) {
31-
tprecode16to8(name, len, name16);
35+
tprecode16to8(name8, sizeof(name8), name16);
36+
if (memccpy(name, name8, '\0', len)) {
37+
return 0;
38+
} else {
39+
return enametoolong();
40+
}
3241
return 0;
3342
} else {
3443
return __winerr();

libc/calls/gethostname.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,60 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20+
#include "libc/calls/strace.internal.h"
2021
#include "libc/calls/syscall_support-sysv.internal.h"
2122
#include "libc/dce.h"
23+
#include "libc/intrin/kprintf.h"
2224
#include "libc/nt/enum/computernameformat.h"
2325
#include "libc/sysv/errfuns.h"
2426

27+
#define KERN_HOSTNAME 10
28+
2529
/**
26-
* Returns name of host system, e.g.
30+
* Returns name of current host.
31+
*
32+
* For example, if the fully-qualified hostname is "host.domain.example"
33+
* then this SHOULD return "host" however that might not be the case; it
34+
* depends on how the host machine is configured. It's fair to say if it
35+
* has a dot, it's a FQDN, otherwise it's a node.
36+
*
37+
* The nul / mutation semantics are tricky. Here is some safe copypasta:
38+
*
39+
* char host[254];
40+
* if (gethostname(host, sizeof(host))) {
41+
* strcpy(host, "localhost");
42+
* }
2743
*
28-
* pheidippides.domain.example
29-
* ^^^^^^^^^^^^
44+
* On Linux this is the same as `/proc/sys/kernel/hostname`.
3045
*
31-
* @return 0 on success or -1 w/ errno
46+
* @param name receives output name, which is guaranteed to be complete
47+
* and have a nul-terminator if this function return zero
48+
* @param len is size of `name` consider using `DNS_NAME_MAX + 1` (254)
49+
* @raise EINVAL if `len` is negative
50+
* @raise EFAULT if `name` is an invalid address
51+
* @raise ENAMETOOLONG if the underlying system call succeeded, but the
52+
* returned hostname had a length equal to or greater than `len` in
53+
* which case this error is raised and the buffer is modified, with
54+
* as many bytes of hostname as possible excluding a nul-terminator
55+
* @return 0 on success, or -1 w/ errno
3256
*/
3357
int gethostname(char *name, size_t len) {
34-
if (len < 1) return einval();
35-
if (!name) return efault();
36-
if (!IsWindows()) {
37-
if (!IsBsd()) {
38-
return gethostname_linux(name, len);
39-
} else {
40-
return gethostname_bsd(name, len);
41-
}
58+
int rc;
59+
if (len < 0) {
60+
rc = einval();
61+
} else if (!len) {
62+
rc = 0;
63+
} else if (!name) {
64+
rc = efault();
65+
} else if (IsLinux()) {
66+
rc = gethostname_linux(name, len);
67+
} else if (IsBsd()) {
68+
rc = gethostname_bsd(name, len, KERN_HOSTNAME);
69+
} else if (IsWindows()) {
70+
rc = gethostname_nt(name, len, kNtComputerNamePhysicalDnsHostname);
4271
} else {
43-
return gethostname_nt(name, len, kNtComputerNamePhysicalDnsHostname);
72+
rc = enosys();
4473
}
74+
STRACE("gethostname([%#.*s], %'zu) → %d% m", len, name, len, rc);
75+
return rc;
4576
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_
2+
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_
3+
#if !(__ASSEMBLER__ + __LINKER__ + 0)
4+
COSMOPOLITAN_C_START_
5+
6+
struct utsname_linux {
7+
char sysname[65];
8+
char nodename[65];
9+
char release[65];
10+
char version[65];
11+
char machine[65];
12+
char domainname[65];
13+
};
14+
15+
int sys_uname_linux(struct utsname_linux *) asm("sys_uname");
16+
17+
COSMOPOLITAN_C_END_
18+
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
19+
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UTSNAME_LINUX_INTERNAL_H_ */

libc/calls/struct/utsname-netbsd.internal.h

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)