Add script.com and whois.com courtesy of FreeBSD

This commit is contained in:
Justine Tunney 2022-09-13 20:11:09 -07:00
parent 654ceaba7d
commit 1ad2f530f9
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
33 changed files with 1735 additions and 265 deletions

522
examples/script.c Normal file
View file

@ -0,0 +1,522 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Copyright (c) 2010, 2012 David E. O'Brien
Copyright (c) 1980, 1992, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bswap.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/bsd.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/select.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/termios.h"
#include "libc/time/time.h"
#include "third_party/getopt/getopt.h"
// clang-format off
/**
* @fileoverview Terminal Screencast Recorder / Player, e.g.
*
* make o//examples/script.com
* o//examples/script.com -r
* # type stuff..
* # CTRL-D
* o//examples/script.com -p typescript
*
* @note works on Linux, OpenBSD, NetBSD, FreeBSD, MacOS
* @see https://asciinema.org/
*/
asm(".ident\t\"\\n\\n\
FreeBSD Script (BSD-3 License)\\n\
Copyright (c) 2010, 2012 David E. O'Brien\\n\
Copyright (c) 1980, 1992, 1993\\n\
\tThe Regents of the University of California.\\n\
\tAll rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
#define DEF_BUF 65536
struct stamp {
uint64_t scr_len; /* amount of data */
uint64_t scr_sec; /* time it arrived in seconds... */
uint32_t scr_usec; /* ...and microseconds */
uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
};
static FILE *fscript;
static int master, slave;
static int child;
static const char *fname;
static char *fmfname;
static int qflg, ttyflg;
static int usesleep, rawout, showexit;
static struct termios tt;
static void done(int) wontreturn;
static void doshell(char **);
static void finish(void);
static void record(FILE *, char *, size_t, int);
static void consume(FILE *, off_t, char *, int);
static void playback(FILE *) wontreturn;
static void usage(void);
int
main(int argc, char *argv[])
{
int cc;
struct termios rtt, stt;
struct winsize win;
struct timeval tv, *tvp;
time_t tvec, start;
static char obuf[BUFSIZ];
static char ibuf[BUFSIZ];
fd_set rfd;
int aflg, Fflg, kflg, pflg, ch, k, n;
int flushtime, readstdin;
int fm_fd, fm_log;
aflg = Fflg = kflg = pflg = 0;
usesleep = 1;
rawout = 0;
flushtime = 30;
fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
warning. (not needed w/clang) */
showexit = 0;
while ((ch = getopt(argc, argv, "adeFfkpqrt:")) != -1)
switch(ch) {
case 'a':
aflg = 1;
break;
case 'd':
usesleep = 0;
break;
case 'e': /* Default behavior, accepted for linux compat */
break;
case 'F':
Fflg = 1;
break;
case 'k':
kflg = 1;
break;
case 'p':
pflg = 1;
break;
case 'q':
qflg = 1;
break;
case 'r':
rawout = 1;
break;
case 't':
flushtime = atoi(optarg);
if (flushtime < 0)
err(1, "invalid flush time %d", flushtime);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0) {
fname = argv[0];
argv++;
argc--;
} else
fname = "typescript";
if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
err(1, "%s", fname);
if (pflg)
playback(fscript);
if (tcgetattr(STDIN_FILENO, &tt) == -1 ||
ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1) {
if (errno != ENOTTY) /* For debugger. */
err(1, "tcgetattr/ioctl");
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
err(1, "openpty");
} else {
if (openpty(&master, &slave, NULL, &tt, &win) == -1)
err(1, "openpty");
ttyflg = 1;
}
if (rawout)
record(fscript, NULL, 0, 's');
if (!qflg) {
tvec = time(NULL);
printf("Script started, output file is %s\n", fname);
if (!rawout) {
fprintf(fscript, "Script started on %s",
ctime(&tvec));
if (argv[0]) {
showexit = 1;
fprintf(fscript, "Command: ");
for (k = 0 ; argv[k] ; ++k)
fprintf(fscript, "%s%s", k ? " " : "",
argv[k]);
fprintf(fscript, "\n");
}
}
fflush(fscript);
}
if (ttyflg) {
rtt = tt;
cfmakeraw(&rtt);
rtt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
}
child = fork();
if (child < 0) {
warn("fork");
done(1);
}
if (child == 0) {
doshell(argv);
}
close(slave);
start = tvec = time(0);
readstdin = 1;
for (;;) {
FD_ZERO(&rfd);
FD_SET(master, &rfd);
if (readstdin)
FD_SET(STDIN_FILENO, &rfd);
if (!readstdin && ttyflg) {
tv.tv_sec = 1;
tv.tv_usec = 0;
tvp = &tv;
readstdin = 1;
} else if (flushtime > 0) {
tv.tv_sec = flushtime - (tvec - start);
tv.tv_usec = 0;
tvp = &tv;
} else {
tvp = NULL;
}
n = select(master + 1, &rfd, 0, 0, tvp);
if (n < 0 && errno != EINTR)
break;
if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
cc = read(STDIN_FILENO, ibuf, BUFSIZ);
if (cc < 0)
break;
if (cc == 0) {
if (tcgetattr(master, &stt) == 0 &&
(stt.c_lflag & ICANON) != 0) {
write(master, &stt.c_cc[VEOF], 1);
}
readstdin = 0;
}
if (cc > 0) {
if (rawout)
record(fscript, ibuf, cc, 'i');
write(master, ibuf, cc);
if (kflg && tcgetattr(master, &stt) >= 0 &&
((stt.c_lflag & ECHO) == 0)) {
fwrite(ibuf, 1, cc, fscript);
}
}
}
if (n > 0 && FD_ISSET(master, &rfd)) {
cc = read(master, obuf, sizeof (obuf));
if (cc <= 0)
break;
write(STDOUT_FILENO, obuf, cc);
if (rawout)
record(fscript, obuf, cc, 'o');
else
fwrite(obuf, 1, cc, fscript);
}
tvec = time(0);
if (tvec - start >= flushtime) {
fflush(fscript);
start = tvec;
}
if (Fflg)
fflush(fscript);
}
finish();
done(0);
}
static void
usage(void)
{
fprintf(stderr,
"usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
exit(1);
}
static void
finish(void)
{
int e, status;
if (waitpid(child, &status, 0) == child) {
if (WIFEXITED(status))
e = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
e = WTERMSIG(status);
else /* can't happen */
e = 1;
done(e);
}
}
static void
doshell(char **av)
{
const char *shell;
shell = getenv("SHELL");
if (shell == NULL)
shell = _PATH_BSHELL;
close(master);
fclose(fscript);
free(fmfname);
login_tty(slave);
setenv("SCRIPT", fname, 1);
if (av[0]) {
execvp(av[0], av);
warn("%s", av[0]);
} else {
execl(shell, shell, "-i", 0);
warn("%s", shell);
}
exit(1);
}
static void
done(int eno)
{
time_t tvec;
if (ttyflg)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
tvec = time(NULL);
if (rawout)
record(fscript, NULL, 0, 'e');
if (!qflg) {
if (!rawout) {
if (showexit)
fprintf(fscript, "\nCommand exit status:"
" %d", eno);
fprintf(fscript,"\nScript done on %s",
ctime(&tvec));
}
printf("\nScript done, output file is %s\n", fname);
}
fclose(fscript);
close(master);
exit(eno);
}
static void
record(FILE *fp, char *buf, size_t cc, int direction)
{
struct iovec iov[2];
struct stamp stamp;
struct timeval tv;
gettimeofday(&tv, NULL);
stamp.scr_len = cc;
stamp.scr_sec = tv.tv_sec;
stamp.scr_usec = tv.tv_usec;
stamp.scr_direction = direction;
iov[0].iov_len = sizeof(stamp);
iov[0].iov_base = &stamp;
iov[1].iov_len = cc;
iov[1].iov_base = buf;
if (writev(fileno(fp), &iov[0], 2) == -1)
err(1, "writev");
}
static void
consume(FILE *fp, off_t len, char *buf, int reg)
{
size_t l;
if (reg) {
if (fseeko(fp, len, SEEK_CUR) == -1)
err(1, NULL);
}
else {
while (len > 0) {
l = MIN(DEF_BUF, len);
if (fread(buf, sizeof(char), l, fp) != l)
err(1, "cannot read buffer");
len -= l;
}
}
}
#define swapstamp(stamp) do { \
if (stamp.scr_direction > 0xff) { \
stamp.scr_len = bswap_64(stamp.scr_len); \
stamp.scr_sec = bswap_64(stamp.scr_sec); \
stamp.scr_usec = bswap_32(stamp.scr_usec); \
stamp.scr_direction = bswap_32(stamp.scr_direction); \
} \
} while (0/*CONSTCOND*/)
static void
termset(void)
{
struct termios traw;
if (tcgetattr(STDOUT_FILENO, &tt) == -1) {
if (errno != ENOTTY) /* For debugger. */
err(1, "tcgetattr");
return;
}
ttyflg = 1;
traw = tt;
cfmakeraw(&traw);
traw.c_lflag |= ISIG;
tcsetattr(STDOUT_FILENO, TCSANOW, &traw);
}
static void
termreset(void)
{
if (ttyflg) {
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tt);
ttyflg = 0;
}
}
static void
playback(FILE *fp)
{
struct timespec tsi, tso;
struct stamp stamp;
struct stat pst;
static char buf[DEF_BUF];
off_t nread, save_len;
size_t l;
time_t tclock;
int reg;
if (fstat(fileno(fp), &pst) == -1)
err(1, "fstat failed");
reg = S_ISREG(pst.st_mode);
for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
if (reg)
err(1, "reading playback header");
else
break;
}
swapstamp(stamp);
save_len = sizeof(stamp);
if (reg && stamp.scr_len >
(uint64_t)(pst.st_size - save_len) - nread)
errx(1, "invalid stamp");
save_len += stamp.scr_len;
tclock = stamp.scr_sec;
tso.tv_sec = stamp.scr_sec;
tso.tv_nsec = stamp.scr_usec * 1000;
switch (stamp.scr_direction) {
case 's':
if (!qflg)
printf("Script started on %s",
ctime(&tclock));
tsi = tso;
consume(fp, stamp.scr_len, buf, reg);
termset();
atexit(termreset);
break;
case 'e':
termreset();
if (!qflg)
printf("\nScript done on %s",
ctime(&tclock));
consume(fp, stamp.scr_len, buf, reg);
break;
case 'i':
/* throw input away */
consume(fp, stamp.scr_len, buf, reg);
break;
case 'o':
tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
if (tsi.tv_nsec < 0) {
tsi.tv_sec -= 1;
tsi.tv_nsec += 1000000000;
}
if (usesleep)
nanosleep(&tsi, NULL);
tsi = tso;
while (stamp.scr_len > 0) {
l = MIN(DEF_BUF, stamp.scr_len);
if (fread(buf, sizeof(char), l, fp) != l)
err(1, "cannot read buffer");
write(STDOUT_FILENO, buf, l);
stamp.scr_len -= l;
}
break;
default:
errx(1, "invalid direction");
}
}
fclose(fp);
exit(0);
}

100
examples/script.txt Normal file
View file

@ -0,0 +1,100 @@
SCRIPT(1) Cosmopolitan General Commands Manual SCRIPT(1)
𝐍𝐀𝐌𝐄
𝘀𝗰𝗿𝗶𝗽𝘁 — make typescript of terminal session
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
𝘀𝗰𝗿𝗶𝗽𝘁 [-𝗮𝗱𝗲𝗳𝗸𝗽𝗾𝗿] [-𝐅 p̲i̲p̲e̲] [-𝘁 t̲i̲m̲e̲] [f̲i̲l̲e̲ [c̲o̲m̲m̲a̲n̲d̲ .̲.̲.̲]]
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility makes a typescript of everything printed on your termi
nal. It is useful for students who need a hardcopy record of an interac
tive session as proof of an assignment, as the typescript file can be
printed out later with lpr(1).
If the argument f̲i̲l̲e̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 saves all dialogue in f̲i̲l̲e̲. If no
file name is given, the typescript is saved in the file t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲.
If the argument c̲o̲m̲m̲a̲n̲d̲ is given, 𝘀𝗰𝗿𝗶𝗽𝘁 will run the specified command
with an optional argument vector instead of an interactive shell.
The following options are available:
-𝗮 Append the output to f̲i̲l̲e̲ or t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲, retaining the prior con
tents.
-𝗱 When playing back a session with the -𝗽 flag, do not sleep between
records when playing back a timestamped session.
-𝗲 Accepted for compatibility with u̲t̲i̲l̲-̲l̲i̲n̲u̲x̲ 𝘀𝗰𝗿𝗶𝗽𝘁. The child com
mand exit status is always the exit status of 𝘀𝗰𝗿𝗶𝗽𝘁.
-𝐅 p̲i̲p̲e̲
Immediately flush output after each write. This will allow a user
to create a named pipe using mkfifo(1) and another user may watch
the live session using a utility like cat(1).
-𝗸 Log keys sent to the program as well as output.
-𝗽 Play back a session recorded with the -𝗿 flag in real time.
-𝗾 Run in quiet mode, omit the start, stop and command status mes
sages.
-𝗿 Record a session with input, output, and timestamping.
-𝘁 t̲i̲m̲e̲
Specify the interval at which the script output file will be
flushed to disk, in seconds. A value of 0 causes 𝘀𝗰𝗿𝗶𝗽𝘁 to flush
after every character I/O event. The default interval is 30 sec
onds.
The script ends when the forked shell (or command) exits (a c̲o̲n̲t̲r̲o̲l̲-̲D̲ to
exit the Bourne shell (sh(1)), and e̲x̲i̲t̲, l̲o̲g̲o̲u̲t̲ or c̲o̲n̲t̲r̲o̲l̲-̲D̲ (if i̲g̲n̲o̲r̲e̲e̲o̲f̲
is not set) for the C-shell, csh(1)).
Certain interactive commands, such as vi(1), create garbage in the type
script file. The 𝘀𝗰𝗿𝗶𝗽𝘁 utility works best with commands that do not ma
nipulate the screen. The results are meant to emulate a hardcopy terminal,
not an addressable one.
𝐄𝐍𝐕𝐈𝐑𝐎𝐍𝐌𝐄𝐍𝐓
The following environment variables are utilized by 𝘀𝗰𝗿𝗶𝗽𝘁:
SCRIPT
The SCRIPT environment variable is added to the sub-shell. If
SCRIPT already existed in the users environment, its value is over
written within the sub-shell. The value of SCRIPT is the name of
the t̲y̲p̲e̲s̲c̲r̲i̲p̲t̲ file.
SHELL If the variable SHELL exists, the shell forked by 𝘀𝗰𝗿𝗶𝗽𝘁 will be
that shell. If SHELL is not set, the Bourne shell is assumed.
(Most shells set this variable automatically).
𝐒𝐄𝐄 𝐀𝐋𝐒𝐎
csh(1) (for the h̲i̲s̲t̲o̲r̲y̲ mechanism)
𝐇𝐈𝐒𝐓𝐎𝐑𝐘
The 𝘀𝗰𝗿𝗶𝗽𝘁 command appeared in 3.0BSD.
The -𝗱, -𝗽 and -𝗿 options first appeared in NetBSD 2.0 and were ported to
FreeBSD 9.2.
𝐁𝐔𝐆𝐒
The 𝘀𝗰𝗿𝗶𝗽𝘁 utility places 𝗲𝘃𝗲𝗿𝘆𝘁𝗵𝗶𝗻𝗴 in the log file, including linefeeds
and backspaces. This is not what the naive user expects.
It is not possible to specify a command without also naming the script file
because of argument parsing compatibility issues.
When running in -𝗸 mode, echo cancelling is far from ideal. The slave ter
minal mode is checked for ECHO mode to check when to avoid manual echo log
ging. This does not work when the terminal is in a raw mode where the pro
gram being run is doing manual echo.
If 𝘀𝗰𝗿𝗶𝗽𝘁 reads zero bytes from the terminal, it switches to a mode when it
only attempts to read once a second until there is data to read. This pre
vents 𝘀𝗰𝗿𝗶𝗽𝘁 from spinning on zero-byte reads, but might cause a 1-second
delay in processing of user input.
BSD September 1, 2020 BSD

617
examples/whois.c Normal file
View file

@ -0,0 +1,617 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Copyright (c) 1980, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#include "libc/calls/calls.h"
#include "libc/dns/dns.h"
#include "libc/errno.h"
#include "libc/log/bsd.h"
#include "libc/mem/fmt.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sock.h"
#include "third_party/getopt/getopt.h"
// clang-format off
asm(".ident\t\"\\n\\n\
FreeBSD Whois (BSD-3 License)\\n\
Copyright (c) 1980, 1993\\n\
\tThe Regents of the University of California.\\n\
\tAll rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
#define ABUSEHOST "whois.abuse.net"
#define ANICHOST "whois.arin.net"
#define DENICHOST "whois.denic.de"
#define DKNICHOST "whois.dk-hostmaster.dk"
#define FNICHOST "whois.afrinic.net"
#define GNICHOST "whois.nic.gov"
#define IANAHOST "whois.iana.org"
#define INICHOST "whois.internic.net"
#define KNICHOST "whois.krnic.net"
#define LNICHOST "whois.lacnic.net"
#define MNICHOST "whois.ra.net"
#define PDBHOST "whois.peeringdb.com"
#define PNICHOST "whois.apnic.net"
#define QNICHOST_TAIL ".whois-servers.net"
#define RNICHOST "whois.ripe.net"
#define VNICHOST "whois.verisign-grs.com"
#define DEFAULT_PORT "whois"
#define WHOIS_RECURSE 0x01
#define WHOIS_QUICK 0x02
#define WHOIS_SPAM_ME 0x04
#define CHOPSPAM ">>> Last update of WHOIS database:"
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
#define SCAN(p, end, check) \
while ((p) < (end)) \
if (check) ++(p); \
else break
static struct {
const char *suffix, *server;
} whoiswhere[] = {
/* Various handles */
{ "-ARIN", ANICHOST },
{ "-NICAT", "at" QNICHOST_TAIL },
{ "-NORID", "no" QNICHOST_TAIL },
{ "-RIPE", RNICHOST },
/* Nominet's whois server doesn't return referrals to JANET */
{ ".ac.uk", "ac.uk" QNICHOST_TAIL },
{ ".gov.uk", "ac.uk" QNICHOST_TAIL },
{ "", IANAHOST }, /* default */
{ NULL, NULL } /* safety belt */
};
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
static struct {
const char *prefix;
size_t len;
} whois_referral[] = {
WHOIS_REFERRAL("whois:"), /* IANA */
WHOIS_REFERRAL("Whois Server:"),
WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
WHOIS_REFERRAL("ReferralServer: rwhois://"), /* ARIN */
WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
{ NULL, 0 }
};
/*
* We have a list of patterns for RIRs that assert ignorance rather than
* providing referrals. If that happens, we guess that ARIN will be more
* helpful. But, before following a referral to an RIR, we check if we have
* asked that RIR already, and if so we make another guess.
*/
static const char *actually_arin[] = {
"netname: ERX-NETBLOCK\n", /* APNIC */
"netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
NULL
};
static struct {
int loop;
const char *host;
} try_rir[] = {
{ 0, ANICHOST },
{ 0, RNICHOST },
{ 0, PNICHOST },
{ 0, FNICHOST },
{ 0, LNICHOST },
{ 0, NULL }
};
static void
reset_rir(void) {
int i;
for (i = 0; try_rir[i].host != NULL; i++)
try_rir[i].loop = 0;
}
static const char *port = DEFAULT_PORT;
static const char *choose_server(char *);
static struct addrinfo *gethostinfo(const char *, const char *, int);
static void s_asprintf(char **ret, const char *format, ...);
static void usage(void);
static void whois(const char *, const char *, const char *, int);
int
main(int argc, char *argv[])
{
const char *country, *host;
int ch, flags;
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif
country = host = NULL;
flags = 0;
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
switch (ch) {
case 'a':
host = ANICHOST;
break;
case 'A':
host = PNICHOST;
break;
case 'b':
host = ABUSEHOST;
break;
case 'c':
country = optarg;
break;
case 'f':
host = FNICHOST;
break;
case 'g':
host = GNICHOST;
break;
case 'h':
host = optarg;
break;
case 'i':
host = INICHOST;
break;
case 'I':
host = IANAHOST;
break;
case 'k':
host = KNICHOST;
break;
case 'l':
host = LNICHOST;
break;
case 'm':
host = MNICHOST;
break;
case 'p':
port = optarg;
break;
case 'P':
host = PDBHOST;
break;
case 'Q':
flags |= WHOIS_QUICK;
break;
case 'r':
host = RNICHOST;
break;
case 'R':
flags |= WHOIS_RECURSE;
break;
case 'S':
flags |= WHOIS_SPAM_ME;
break;
case '?':
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (!argc || (country != NULL && host != NULL))
usage();
/*
* If no host or country is specified, rely on referrals from IANA.
*/
if (host == NULL && country == NULL) {
if ((host = getenv("WHOIS_SERVER")) == NULL &&
(host = getenv("RA_SERVER")) == NULL) {
if (!(flags & WHOIS_QUICK))
flags |= WHOIS_RECURSE;
}
}
while (argc-- > 0) {
if (country != NULL) {
char *qnichost;
s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
whois(*argv, qnichost, port, flags);
free(qnichost);
} else
whois(*argv, host != NULL ? host :
choose_server(*argv), port, flags);
reset_rir();
argv++;
}
exit(0);
}
static const char *
choose_server(char *domain)
{
size_t len = strlen(domain);
int i;
for (i = 0; whoiswhere[i].suffix != NULL; i++) {
size_t suffix_len = strlen(whoiswhere[i].suffix);
if (len > suffix_len &&
strcasecmp(domain + len - suffix_len,
whoiswhere[i].suffix) == 0)
return (whoiswhere[i].server);
}
errx(EX_SOFTWARE, "no default whois server");
}
static struct addrinfo *
gethostinfo(const char *host, const char *hport, int exit_on_noname)
{
struct addrinfo hints, *res;
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
error = getaddrinfo(host, hport, &hints, &res);
if (error && (exit_on_noname || error != EAI_NONAME))
err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
return (res);
}
/*
* Wrapper for asprintf(3) that exits on error.
*/
static void
s_asprintf(char **ret, const char *format, ...)
{
va_list ap;
va_start(ap, format);
if (vasprintf(ret, format, ap) == -1) {
va_end(ap);
err(EX_OSERR, "vasprintf()");
}
va_end(ap);
}
static int
connect_to_any_host(struct addrinfo *hostres)
{
struct addrinfo *res;
nfds_t i, j;
size_t count;
struct pollfd *fds;
int timeout = 180, s = -1;
for (res = hostres, count = 0; res; res = res->ai_next)
count++;
fds = calloc(count, sizeof(*fds));
if (fds == NULL)
err(EX_OSERR, "calloc()");
/*
* Traverse the result list elements and make non-block
* connection attempts.
*/
count = i = 0;
for (res = hostres; res != NULL; res = res->ai_next) {
s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
res->ai_protocol);
if (s < 0)
continue;
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS) {
/* Add the socket to poll list */
fds[i].fd = s;
fds[i].events = POLLERR | POLLHUP |
POLLIN | POLLOUT;
/*
* From here until a socket connects, the
* socket fd is owned by the fds[] poll array.
*/
s = -1;
count++;
i++;
} else {
close(s);
s = -1;
/*
* Poll only if we have something to poll,
* otherwise just go ahead and try next
* address
*/
if (count == 0)
continue;
}
} else
goto done;
/*
* If we are at the last address, poll until a connection is
* established or we failed all connection attempts.
*/
if (res->ai_next == NULL)
timeout = INFTIM;
/*
* Poll the watched descriptors for successful connections:
* if we still have more untried resolved addresses, poll only
* once; otherwise, poll until all descriptors have errors,
* which will be considered as ETIMEDOUT later.
*/
do {
int n;
n = poll(fds, i, timeout);
if (n == 0) {
/*
* No event reported in time. Try with a
* smaller timeout (but cap at 2-3ms)
* after a new host have been added.
*/
if (timeout >= 3)
timeout >>= 1;
break;
} else if (n < 0) {
/*
* errno here can only be EINTR which we would
* want to clean up and bail out.
*/
s = -1;
goto done;
}
/*
* Check for the event(s) we have seen.
*/
for (j = 0; j < i; j++) {
if (fds[j].fd == -1 || fds[j].events == 0 ||
fds[j].revents == 0)
continue;
if (fds[j].revents & ~(POLLIN | POLLOUT)) {
close(fds[j].fd);
fds[j].fd = -1;
fds[j].events = 0;
count--;
continue;
} else if (fds[j].revents & (POLLIN | POLLOUT)) {
/* Connect succeeded. */
s = fds[j].fd;
fds[j].fd = -1;
goto done;
}
}
} while (timeout == INFTIM && count != 0);
}
/* All attempts were failed */
s = -1;
if (count == 0)
errno = ETIMEDOUT;
done:
/* Close all watched fds except the succeeded one */
for (j = 0; j < i; j++)
if (fds[j].fd != -1)
close(fds[j].fd);
free(fds);
return (s);
}
static void
whois(const char *query, const char *hostname, const char *hostport, int flags)
{
FILE *fp;
struct addrinfo *hostres;
char *buf, *host, *nhost, *nport, *p;
int comment, s, f;
size_t len, i;
hostres = gethostinfo(hostname, hostport, 1);
s = connect_to_any_host(hostres);
if (s == -1)
err(EX_OSERR, "connect()");
/* Restore default blocking behavior. */
if ((f = fcntl(s, F_GETFL)) == -1)
err(EX_OSERR, "fcntl()");
f &= ~O_NONBLOCK;
if (fcntl(s, F_SETFL, f) == -1)
err(EX_OSERR, "fcntl()");
fp = fdopen(s, "r+");
if (fp == NULL)
err(EX_OSERR, "fdopen()");
if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, DENICHOST) == 0 ||
strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
const char *q;
int idn = 0;
for (q = query; *q != '\0'; q++)
if (!isascii(*q))
idn = 1;
fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
} else if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, DKNICHOST) == 0 ||
strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
fprintf(fp, "--show-handles %s\r\n", query);
else if ((flags & WHOIS_SPAM_ME) ||
strchr(query, ' ') != NULL)
fprintf(fp, "%s\r\n", query);
else if (strcasecmp(hostname, ANICHOST) == 0) {
if (strncasecmp(query, "AS", 2) == 0 &&
strspn(query+2, "0123456789") == strlen(query+2))
fprintf(fp, "+ a %s\r\n", query+2);
else
fprintf(fp, "+ %s\r\n", query);
} else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
fprintf(fp, "domain %s\r\n", query);
else
fprintf(fp, "%s\r\n", query);
fflush(fp);
comment = 0;
if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, ANICHOST) == 0 ||
strcasecmp(hostname, RNICHOST) == 0)) {
comment = 2;
}
nhost = NULL;
while ((buf = fgetln(fp, &len)) != NULL) {
/* Nominet */
if (!(flags & WHOIS_SPAM_ME) &&
len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
break;
/* RIRs */
if (comment == 1 && buf[0] == '#')
break;
else if (comment == 2) {
if (strchr("#%\r\n", buf[0]) != NULL)
continue;
else
comment = 1;
}
printf("%.*s", (int)len, buf);
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
for (i = 0; whois_referral[i].prefix != NULL; i++) {
p = buf;
SCAN(p, buf+len, *p == ' ');
if (strncasecmp(p, whois_referral[i].prefix,
whois_referral[i].len) != 0)
continue;
p += whois_referral[i].len;
SCAN(p, buf+len, *p == ' ');
host = p;
SCAN(p, buf+len, ishost(*p));
if (p > host) {
char *pstr;
s_asprintf(&nhost, "%.*s",
(int)(p - host), host);
if (*p != ':') {
s_asprintf(&nport, "%s", port);
break;
}
pstr = ++p;
SCAN(p, buf+len, isdigit(*p));
if (p > pstr && (p - pstr) < 6) {
s_asprintf(&nport, "%.*s",
(int)(p - pstr), pstr);
break;
}
/* Invalid port; don't recurse */
free(nhost);
nhost = NULL;
}
break;
}
for (i = 0; actually_arin[i] != NULL; i++) {
if (strncmp(buf, actually_arin[i], len) == 0) {
s_asprintf(&nhost, "%s", ANICHOST);
s_asprintf(&nport, "%s", port);
break;
}
}
}
/* Verisign etc. */
if (!(flags & WHOIS_SPAM_ME) &&
len >= sizeof(CHOPSPAM)-1 &&
(strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
printf("\n");
break;
}
}
fclose(fp);
freeaddrinfo(hostres);
f = 0;
for (i = 0; try_rir[i].host != NULL; i++) {
/* Remember visits to RIRs */
if (try_rir[i].loop == 0 &&
strcasecmp(try_rir[i].host, hostname) == 0)
try_rir[i].loop = 1;
/* Do we need to find an alternative RIR? */
if (try_rir[i].loop != 0 && nhost != NULL &&
strcasecmp(try_rir[i].host, nhost) == 0) {
free(nhost);
nhost = NULL;
free(nport);
nport = NULL;
f = 1;
}
}
if (f) {
/* Find a replacement RIR */
for (i = 0; try_rir[i].host != NULL; i++) {
if (try_rir[i].loop == 0) {
s_asprintf(&nhost, "%s", try_rir[i].host);
s_asprintf(&nport, "%s", port);
break;
}
}
}
if (nhost != NULL) {
/* Ignore self-referrals */
if (strcasecmp(hostname, nhost) != 0) {
printf("# %s\n\n", nhost);
whois(query, nhost, nport, flags);
}
free(nhost);
free(nport);
}
}
static void
usage(void)
{
fprintf(stderr,
"usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
"[-p port] name ...\n");
exit(EX_USAGE);
}

View file

@ -16,6 +16,27 @@
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/syscall-sysv.internal.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/termios.h"
int grantpt(int fd) { return 0; } /**
* Grants access to subordinate pseudoteletypewriter.
*
* @return 0 on success, or -1 w/ errno
* @raise EBADF if fd isn't open
* @raise EINVAL if fd is valid but not associated with pty
* @raise EACCES if pseudoterminal couldn't be accessed
*/
int grantpt(int fd) {
int rc;
if (IsXnu()) {
rc = sys_ioctl(fd, TIOCPTYGRANT);
} else {
rc = _isptmaster(fd);
}
STRACE("grantpt(%d) → %d% m", fd, rc);
return rc;
}

View file

@ -12,13 +12,6 @@ COSMOPOLITAN_C_START_
#define kIoMotion ((const int8_t[3]){1, 0, 0}) #define kIoMotion ((const int8_t[3]){1, 0, 0})
struct IoctlPtmGet {
int theduxfd;
int workerfd;
char theduxname[16];
char workername[16];
};
hidden extern struct Fds g_fds; hidden extern struct Fds g_fds;
hidden extern const struct Fd kEmptyFd; hidden extern const struct Fd kEmptyFd;

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,11 +16,23 @@
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/log/bsd.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/termios.h"
wontreturn void(errx)(int eval, const char *fmt, ...) { int _isptmaster(int fd) {
va_list va; if (IsFreebsd()) {
va_start(va, fmt); if (!sys_ioctl(fd, TIOCPTMASTER)) {
(verrx)(eval, fmt, va); return 0;
va_end(va); } else {
if (errno != EBADF) {
errno = EINVAL;
}
return -1;
}
} else {
return 0;
}
} }

View file

@ -18,12 +18,23 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/ioctl.h" #include "libc/calls/ioctl.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/fmt/itoa.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/rop.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h" #include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
struct IoctlPtmGet {
int m;
int s;
char mname[16];
char sname[16];
};
/** /**
* Opens new pseudo teletypewriter. * Opens new pseudo teletypewriter.
@ -37,24 +48,29 @@
*/ */
int openpty(int *mfd, int *sfd, char *name, const struct termios *tio, int openpty(int *mfd, int *sfd, char *name, const struct termios *tio,
const struct winsize *wsz) { const struct winsize *wsz) {
int m, s, n; int m, s, p;
char buf[20]; const char *t;
if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) { struct IoctlPtmGet ptm;
n = 0; RETURN_ON_ERROR((m = posix_openpt(O_RDWR | O_NOCTTY)));
if (!ioctl(m, TIOCSPTLCK, &n) && !ioctl(m, TIOCGPTN, &n)) { if (!IsOpenbsd()) {
if (!name) name = buf; RETURN_ON_ERROR(grantpt(m));
name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v'; RETURN_ON_ERROR(unlockpt(m));
name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's'; if (!(t = ptsname(m))) goto OnError;
name[8] = '/', FormatInt32(name + 9, n); RETURN_ON_ERROR((s = open(t, O_RDWR)));
if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) { } else {
if (tio) ioctl(s, TCSETS, tio); RETURN_ON_ERROR(ioctl(m, PTMGET, &ptm));
if (wsz) ioctl(s, TIOCSWINSZ, wsz);
*mfd = m;
*sfd = s;
return 0;
}
}
close(m); close(m);
m = ptm.m;
s = ptm.s;
t = ptm.sname;
} }
*mfd = m;
*sfd = s;
if (name) strcpy(name, t);
if (tio) ioctl(s, TCSETSF, tio);
if (wsz) ioctl(s, TIOCSWINSZ, wsz);
return 0;
OnError:
if (m != -1) close(m);
return -1; return -1;
} }

View file

@ -16,43 +16,35 @@
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/internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
* Opens new pseudo teletypewriter. * Opens new pseudo teletypewriter.
* *
* @return fd of master pty, or -1 w/ errno
* @params flags is usually O_RDWR|O_NOCTTY * @params flags is usually O_RDWR|O_NOCTTY
* @return file descriptor, or -1 w/ errno * @return file descriptor, or -1 w/ errno
*/ */
int posix_openpt(int flags) { int posix_openpt(int flags) {
int fd, ilduce; int rc;
struct IoctlPtmGet ptm; if ((flags & O_ACCMODE) != O_RDWR) {
if ((flags & O_ACCMODE) != O_RDWR) return einval(); rc = einval();
if (SupportsFreebsd() && } else if (IsLinux() || IsXnu()) {
((fd = sys_posix_openpt(flags)) != -1 || errno != ENOSYS)) { rc = sys_open("/dev/ptmx", flags, 0);
return fd; } else if (IsOpenbsd()) {
} else if ((fd = open("/dev/ptmx", flags)) != -1 || errno != ENOENT) { rc = sys_open("/dev/ptm", flags, 0);
return fd; } else if (IsFreebsd()) {
} else if (SupportsOpenbsd() && rc = sys_posix_openpt(flags);
((fd = open("/dev/ptm", flags)) != -1 || errno != ENOENT)) { if (rc == -1 && errno == ENOSPC) errno = EAGAIN;
if (ioctl(fd, PTMGET, &ptm) != -1) {
close(ptm.workerfd);
ilduce = ptm.theduxfd;
} else {
ilduce = -1;
}
close(fd);
return ilduce;
} else { } else {
return enosys(); rc = enosys();
} }
STRACE("posix_openpt(%#o) → %d% m", flags, rc);
return rc;
} }

View file

@ -17,9 +17,25 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
static char g_ptsname[32]; static char g_ptsname[256];
/**
* Gets name subordinate pseudoteletypewriter.
*
* @return static string path on success, or NULL w/ errno
*/
char *ptsname(int fd) { char *ptsname(int fd) {
return ptsname_r(fd, g_ptsname, sizeof(g_ptsname)) ? g_ptsname : NULL; char *res;
errno_t e;
if (!(e = ptsname_r(fd, g_ptsname, sizeof(g_ptsname)))) {
res = g_ptsname;
} else {
errno = e;
res = 0;
}
STRACE("ptsname(%d) → %s% m", fd, res);
return res;
} }

View file

@ -17,23 +17,69 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/paths.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
errno_t ptsname_r(int fd, char *buf, size_t size) { struct fiodgname_arg {
int pty; int len;
char tb[32]; void *buf;
if (size) { };
if (!buf) return einval();
if (ioctl(fd, TIOCGPTN, &pty) == -1) return errno; static int PtsName(int fd, char *buf, size_t size) {
FormatInt32(stpcpy(tb, "/dev/pts/"), pty); if (size < 9 + 12) return erange();
if (strlen(tb) + 1 >= size) return (errno = ERANGE); if (_isptmaster(fd)) return -1;
stpcpy(buf, tb);
/* TODO(jart): OpenBSD OMG */ if (IsLinux()) {
int pty;
if (sys_ioctl(fd, TIOCGPTN, &pty)) return -1;
buf[0] = '/', buf[1] = 'd', buf[2] = 'e', buf[3] = 'v';
buf[4] = '/', buf[5] = 'p', buf[6] = 't', buf[7] = 's';
buf[8] = '/', FormatInt32(buf + 9, pty);
return 0;
} }
return 0;
if (IsFreebsd()) {
struct fiodgname_arg fgn = {size - 5, buf + 5};
buf[0] = '/', buf[1] = 'd';
buf[2] = 'e', buf[3] = 'v';
buf[4] = '/', buf[5] = 0;
if (sys_ioctl(fd, FIODGNAME, &fgn) == -1) {
if (errno == EINVAL) errno = ERANGE;
return -1;
}
return 0;
}
if (IsXnu()) {
char b2[128];
if (sys_ioctl(fd, TIOCPTYGNAME, b2)) return -1;
if (strlen(b2) + 1 > size) return erange();
strcpy(buf, b2);
return 0;
}
return enosys();
}
/**
* Gets name subordinate pseudoteletypewriter.
*
* @return 0 on success, or errno on error
*/
errno_t ptsname_r(int fd, char *buf, size_t size) {
int rc, e = errno;
if (!PtsName(fd, buf, size)) {
rc = 0;
} else {
rc = errno;
errno = e;
}
return rc;
} }

View file

@ -116,6 +116,7 @@ i64 sys_readlinkat(int, const char *, char *, u64) hidden;
i64 sys_sendfile(i32, i32, i64 *, u64) hidden; i64 sys_sendfile(i32, i32, i64 *, u64) hidden;
i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden; i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 sys_write(i32, const void *, u64) hidden; i64 sys_write(i32, const void *, u64) hidden;
int _isptmaster(int);
u32 sys_getegid(void) hidden; u32 sys_getegid(void) hidden;
u32 sys_geteuid(void) hidden; u32 sys_geteuid(void) hidden;
u32 sys_getgid(void) hidden; u32 sys_getgid(void) hidden;

View file

@ -17,11 +17,32 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/pty.h" #include "libc/sysv/consts/pty.h"
#include "libc/sysv/errfuns.h"
/**
* Unlocks pseudoteletypewriter pair.
*
* @return 0 on success, or -1 w/ errno
* @raise EBADF if fd isn't open
* @raise EINVAL if fd is valid but not associated with pty
*/
int unlockpt(int fd) { int unlockpt(int fd) {
int unlock = 0; int rc;
/* TODO(jart) */ if (IsFreebsd() || IsOpenbsd()) {
return ioctl(fd, TIOCSPTLCK, &unlock); rc = _isptmaster(fd);
} else if (IsXnu()) {
rc = sys_ioctl(fd, TIOCPTYUNLK);
} else if (IsLinux()) {
int unlock = 0;
rc = sys_ioctl(fd, TIOCSPTLCK, &unlock);
} else {
rc = enosys();
}
STRACE("unlockpt(%d) → %d% m", fd, rc);
return rc;
} }

View file

@ -16,9 +16,10 @@
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/mem/alg.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
static const int kCp437iMultimappings[] = { static const int kCp437iMultimappings[] = {
@ -76,7 +77,7 @@ static textstartup void g_cp437i_init() {
unsigned i; unsigned i;
for (i = 0; i < 256; ++i) g_cp437i[i] = kCp437[i] << 8 | i; for (i = 0; i < 256; ++i) g_cp437i[i] = kCp437[i] << 8 | i;
memcpy(g_cp437i + 256, kCp437iMultimappings, sizeof(kCp437iMultimappings)); memcpy(g_cp437i + 256, kCp437iMultimappings, sizeof(kCp437iMultimappings));
djbsort(g_cp437i, ARRAYLEN(g_cp437i)); _intsort(g_cp437i, ARRAYLEN(g_cp437i));
} }
const void *const g_cp437i_ctor[] initarray = {g_cp437i_init}; const void *const g_cp437i_ctor[] initarray = {g_cp437i_init};

View file

@ -2,6 +2,7 @@
#define LIBC_ISYSTEM_STDIO_H_ #define LIBC_ISYSTEM_STDIO_H_
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/mem/fmt.h"
#include "libc/stdio/lock.internal.h" #include "libc/stdio/lock.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h" #include "libc/stdio/temp.h"

4
libc/isystem/sysexits.h Normal file
View file

@ -0,0 +1,4 @@
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_SYSEXITS_H_
#define COSMOPOLITAN_LIBC_ISYSTEM_SYSEXITS_H_
#include "libc/sysv/consts/ex.h"
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_SYSEXITS_H_ */

View file

@ -1,30 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_LOG_BSD_H_ #ifndef COSMOPOLITAN_LIBC_LOG_BSD_H_
#define COSMOPOLITAN_LIBC_LOG_BSD_H_ #define COSMOPOLITAN_LIBC_LOG_BSD_H_
#include "libc/fmt/pflink.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗ void err(int, const char *, ...) wontreturn;
cosmopolitan § logging » berkeley logger void verr(int, const char *, va_list) wontreturn;
*/ void errc(int, int, const char *, ...) wontreturn;
void verrc(int, int, const char *, va_list) wontreturn;
void err(int, const char *, ...) printfesque(2) wontreturn; void errx(int, const char *, ...) wontreturn;
void errx(int, const char *, ...) printfesque(2) wontreturn; void verrx(int, const char *, va_list) wontreturn;
void verr(int, const char *, va_list) paramsnonnull((3)) wontreturn; void warn(const char *, ...);
void verrx(int, const char *, va_list) paramsnonnull((3)) wontreturn; void vwarn(const char *, va_list);
void vwarn(const char *, va_list) paramsnonnull((2)); void warnc(int, const char *, ...);
void vwarnx(const char *, va_list) paramsnonnull((2)); void vwarnc(int, const char *, va_list);
void warn(const char *, ...) printfesque(1); void warnx(const char *, ...);
void warnx(const char *, ...) printfesque(1); void vwarnx(const char *, va_list);
void err_set_exit(void (*)(int));
#define err(EVAL, FMT, ...) (err)(EVAL, PFLINK(FMT), ##__VA_ARGS__)
#define errx(EVAL, FMT, ...) (errx)(EVAL, PFLINK(FMT), ##__VA_ARGS__)
#define verr(EVAL, FMT, VA) (verr)(EVAL, PFLINK(FMT), VA)
#define verrx(EVAL, FMT, VA) (verrx)(EVAL, PFLINK(FMT), VA)
#define vwarn(FMT, VA) (vwarn)(PFLINK(FMT), VA)
#define vwarnx(FMT, VA) (vwarnx)(PFLINK(FMT), VA)
#define warn(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__)
#define warnx(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__)
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,26 +1,194 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright (c) 1993
The Regents of the University of California. All rights reserved.
Permission to use, copy, modify, and/or distribute this software for Redistribution and use in source and binary forms, with or without
any purpose with or without fee is hereby granted, provided that the modification, are permitted provided that the following conditions
above copyright notice and this permission notice appear in all copies. are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
PERFORMANCE OF THIS SOFTWARE. HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/ */
#include "libc/errno.h"
#include "libc/log/bsd.h" #include "libc/log/bsd.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
// clang-format off
wontreturn void(err)(int eval, const char *fmt, ...) { asm(".ident\t\"\\n\\n\
va_list va; FreeBSD Err (BSD-3 License)\\n\
va_start(va, fmt); Copyright (c) 1993\\n\
(verr)(eval, fmt, va); \tThe Regents of the University of California.\\n\
va_end(va); \tAll rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
static FILE *err_file; /* file to use for error output */
static void (*err_exit)(int);
/*
* This is declared to take a `void *' so that the caller is not required
* to include <stdio.h> first. However, it is really a `FILE *', and the
* manual page documents it as such.
*/
void
err_set_file(void *fp)
{
if (fp)
err_file = fp;
else
err_file = stderr;
}
void
err_set_exit(void (*ef)(int))
{
err_exit = ef;
}
void
err(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verrc(eval, errno, fmt, ap);
va_end(ap);
}
void
verr(int eval, const char *fmt, va_list ap)
{
verrc(eval, errno, fmt, ap);
}
void
errc(int eval, int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verrc(eval, code, fmt, ap);
va_end(ap);
}
void
verrc(int eval, int code, const char *fmt, va_list ap)
{
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", program_invocation_name);
if (fmt != NULL) {
vfprintf(err_file, fmt, ap);
fprintf(err_file, ": ");
}
fprintf(err_file, "%s\n", _strerdoc(code));
if (err_exit)
err_exit(eval);
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
verrx(eval, fmt, ap);
va_end(ap);
}
void
verrx(int eval, const char *fmt, va_list ap)
{
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", program_invocation_name);
if (fmt != NULL)
vfprintf(err_file, fmt, ap);
fprintf(err_file, "\n");
if (err_exit)
err_exit(eval);
exit(eval);
}
void
warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnc(errno, fmt, ap);
va_end(ap);
}
void
vwarn(const char *fmt, va_list ap)
{
vwarnc(errno, fmt, ap);
}
void
warnc(int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnc(code, fmt, ap);
va_end(ap);
}
void
vwarnc(int code, const char *fmt, va_list ap)
{
int saved_errno;
saved_errno = errno;
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", program_invocation_name);
if (fmt != NULL) {
vfprintf(err_file, fmt, ap);
fprintf(err_file, ": ");
}
fprintf(err_file, "%s\n", strerror(code));
errno = saved_errno;
}
void
warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
}
void
vwarnx(const char *fmt, va_list ap)
{
int saved_errno;
saved_errno = errno;
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", program_invocation_name);
if (fmt != NULL)
vfprintf(err_file, fmt, ap);
fprintf(err_file, "\n");
errno = saved_errno;
} }

View file

@ -1,31 +0,0 @@
/*-*- 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/log/bsd.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
wontreturn void(verrx)(int eval, const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s: ", program_invocation_name, RED2, "ERROR",
RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
exit(eval);
}

View file

@ -1,30 +0,0 @@
/*-*- 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/log/bsd.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
void(vwarn)(const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s[%m]: ", program_invocation_name, SUBTLE,
"WARNING", RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
}

View file

@ -1,26 +0,0 @@
/*-*- 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/log/bsd.h"
void(warn)(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(vwarn)(fmt, va);
va_end(va);
}

View file

@ -1,26 +0,0 @@
/*-*- 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/log/bsd.h"
void(warnx)(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(vwarnx)(fmt, va);
va_end(va);
}

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,37 @@
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/safemacros.internal.h" #include "libc/calls/calls.h"
#include "libc/log/bsd.h" #include "libc/calls/ioctl.h"
#include "libc/log/color.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/log/internal.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/runtime/utmp.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
wontreturn void(verr)(int eval, const char *fmt, va_list va) { /**
fprintf(stderr, * Prepares terminal for login.
"%s: %s%s%s[%m]: ", firstnonnull(program_invocation_name, "unknown"), *
RED2, "ERROR", RESET); * @return 0 on success, or -1 w/ errno
if (fmt) (vfprintf)(stderr, fmt, va); * @raise ENOSYS on Windows and Metal
fprintf(stderr, "\n"); * @raise EPERM if terminal is already controlling another sid
exit(eval); */
int login_tty(int fd) {
int rc;
if (IsLinux() || IsBsd()) {
setsid();
if (!sys_ioctl(fd, TIOCSCTTY, 0)) {
for (int i = 0; i < 3; ++i) dup2(fd, i);
if (fd > 2) close(fd);
rc = 0;
} else {
rc = -1;
}
} else {
rc = enosys();
}
STRACE("login_tty(%d) → %d% m", fd, rc);
return rc;
} }

View file

@ -88,12 +88,14 @@ long gethostid(void);
int sethostid(long); int sethostid(long);
char *getlogin(void); char *getlogin(void);
int getlogin_r(char *, size_t); int getlogin_r(char *, size_t);
int login_tty(int);
int getpagesize(void); int getpagesize(void);
int syncfs(int); int syncfs(int);
int vhangup(void); int vhangup(void);
int getdtablesize(void); int getdtablesize(void);
int sethostname(const char *, size_t); int sethostname(const char *, size_t);
int acct(const char *); int acct(const char *);
void _intsort(int *, size_t);
void _longsort(long *, size_t); void _longsort(long *, size_t);
bool _isheap(void *); bool _isheap(void *);
int NtGetVersion(void) pureconst; int NtGetVersion(void) pureconst;

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,15 +16,32 @@
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/log/bsd.h" #include "libc/intrin/strace.internal.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
void(vwarnx)(const char *fmt, va_list va) { static void _intsorter(int *A, size_t n) {
fprintf(stderr, "%s: %s%s%s: ", program_invocation_name, SUBTLE, "WARNING", int t, p;
RESET); size_t i, j;
if (fmt) (vfprintf)(stderr, fmt, va); if (n < 2) return;
fprintf(stderr, "\n"); for (p = A[n / 2], i = 0, j = n - 1;; i++, j--) {
while (A[i] < p) i++;
while (A[j] > p) j--;
if (i >= j) break;
t = A[i];
A[i] = A[j];
A[j] = t;
}
_intsorter(A, i);
_intsorter(A + i, n - i);
}
/**
* Tiny and reasonably fast sorting for ints.
* @see djbsort
*/
void _intsort(int *A, size_t n) {
_intsorter(A, n);
if (n > 1000) {
STRACE("_intsort(%p, %'zu)", A, n);
}
} }

View file

@ -1374,7 +1374,7 @@ syscon termios TIOCCONS 0x541d 0x80047462 0x80047462 0x80047462 0x800474
syscon termios TIOCGETD 0x5424 0x4004741a 0x4004741a 0x4004741a 0x4004741a 0 # boop syscon termios TIOCGETD 0x5424 0x4004741a 0x4004741a 0x4004741a 0x4004741a 0 # boop
syscon termios TIOCNOTTY 0x5422 0x20007471 0x20007471 0x20007471 0x20007471 0 # boop syscon termios TIOCNOTTY 0x5422 0x20007471 0x20007471 0x20007471 0x20007471 0 # boop
syscon termios TIOCNXCL 0x540d 0x2000740e 0x2000740e 0x2000740e 0x2000740e 0 # boop syscon termios TIOCNXCL 0x540d 0x2000740e 0x2000740e 0x2000740e 0x2000740e 0 # boop
syscon termios TIOCSCTTY 0x540e 0x20007461 0x20007461 0x20007461 0x20007461 0 # boop syscon termios TIOCSCTTY 0x540e 0x20007461 0x20007461 0x20007461 0x20007461 0 # makes terminal controlling terminal of calling process (see login_tty)
syscon termios TIOCSETD 0x5423 0x8004741b 0x8004741b 0x8004741b 0x8004741b 0 # boop syscon termios TIOCSETD 0x5423 0x8004741b 0x8004741b 0x8004741b 0x8004741b 0 # boop
syscon termios TIOCSIG 0x40045436 0x2000745f 0x2004745f 0x8004745f 0x8004745f 0 # boop syscon termios TIOCSIG 0x40045436 0x2000745f 0x2004745f 0x8004745f 0x8004745f 0 # boop
syscon termios TIOCSTI 0x5412 0x80017472 0x80017472 0 0 0 # boop syscon termios TIOCSTI 0x5412 0x80017472 0x80017472 0 0 0 # boop
@ -1409,6 +1409,10 @@ syscon termios TIOCSFLAGS 0 0 0 0x8004745c 0x8004745c 0 # boop
syscon termios TIOCSTSTAMP 0 0 0 0x8008745a 0x8008745a 0 # boop syscon termios TIOCSTSTAMP 0 0 0 0x8008745a 0x8008745a 0 # boop
syscon termios ENDRUNDISC 0 0 0 0x9 0x9 0 # boop syscon termios ENDRUNDISC 0 0 0 0x9 0x9 0 # boop
syscon termios TIOCPTMASTER 0 0 0x2000741c 0 0 0 # boop syscon termios TIOCPTMASTER 0 0 0x2000741c 0 0 0 # boop
syscon termios TIOCPTYGRANT 0 0x20007454 0 0 0 0 # xnu grantpt()
syscon termios TIOCPTYUNLK 0 0x20007452 0 0 0 0 # xnu grantpt()
syscon termios TIOCPTYGNAME 0 0x40807453 0 0 0 0 # xnu grantpt()
syscon termios FIODGNAME 0 0 0x80106678 0 0 0 # freebsd ptsname_r()
syscon termios NETGRAPHDISC 0 0 0x6 0 0 0 # boop syscon termios NETGRAPHDISC 0 0 0x6 0 0 0 # boop
syscon termios H4DISC 0 0 0x7 0 0 0 # boop syscon termios H4DISC 0 0 0x7 0 0 0 # boop

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon termios,FIODGNAME,0,0,0x80106678,0,0,0

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon termios,TIOCPTYGNAME,0,0x40807453,0,0,0,0

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon termios,TIOCPTYGRANT,0,0x20007454,0,0,0,0

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon termios,TIOCPTYUNLK,0,0x20007452,0,0,0,0

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_POLL_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_POLL_H_
#include "libc/runtime/symbolic.h" #include "libc/runtime/symbolic.h"
#define INFTIM (-1)
#define POLLERR SYMBOLIC(POLLERR) #define POLLERR SYMBOLIC(POLLERR)
#define POLLHUP SYMBOLIC(POLLHUP) #define POLLHUP SYMBOLIC(POLLHUP)
#define POLLIN SYMBOLIC(POLLIN) #define POLLIN SYMBOLIC(POLLIN)

View file

@ -178,6 +178,10 @@ extern const uint8_t VTIME;
extern const uint8_t VWERASE; extern const uint8_t VWERASE;
extern const uint32_t XCASE; extern const uint32_t XCASE;
extern const uint32_t XTABS; extern const uint32_t XTABS;
extern const uint32_t FIODGNAME;
extern const uint32_t TIOCPTYGRANT;
extern const uint32_t TIOCPTYUNLK;
extern const uint32_t TIOCPTYGNAME;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
@ -250,6 +254,7 @@ COSMOPOLITAN_C_END_
#define EXTA SYMBOLIC(EXTA) #define EXTA SYMBOLIC(EXTA)
#define EXTB SYMBOLIC(EXTB) #define EXTB SYMBOLIC(EXTB)
#define EXTPROC SYMBOLIC(EXTPROC) #define EXTPROC SYMBOLIC(EXTPROC)
#define FIODGNAME SYMBOLIC(FIODGNAME)
#define FLUSHO SYMBOLIC(FLUSHO) #define FLUSHO SYMBOLIC(FLUSHO)
#define H4DISC SYMBOLIC(H4DISC) #define H4DISC SYMBOLIC(H4DISC)
#define HUPCL SYMBOLIC(HUPCL) #define HUPCL SYMBOLIC(HUPCL)
@ -319,6 +324,9 @@ COSMOPOLITAN_C_END_
#define TIOCNXCL SYMBOLIC(TIOCNXCL) #define TIOCNXCL SYMBOLIC(TIOCNXCL)
#define TIOCOUTQ SYMBOLIC(TIOCOUTQ) #define TIOCOUTQ SYMBOLIC(TIOCOUTQ)
#define TIOCPTMASTER SYMBOLIC(TIOCPTMASTER) #define TIOCPTMASTER SYMBOLIC(TIOCPTMASTER)
#define TIOCPTYGNAME SYMBOLIC(TIOCPTYGNAME)
#define TIOCPTYGRANT SYMBOLIC(TIOCPTYGRANT)
#define TIOCPTYUNLK SYMBOLIC(TIOCPTYUNLK)
#define TIOCREMOTE SYMBOLIC(TIOCREMOTE) #define TIOCREMOTE SYMBOLIC(TIOCREMOTE)
#define TIOCSBRK SYMBOLIC(TIOCSBRK) #define TIOCSBRK SYMBOLIC(TIOCSBRK)
#define TIOCSCTTY SYMBOLIC(TIOCSCTTY) #define TIOCSCTTY SYMBOLIC(TIOCSCTTY)

View file

@ -55,17 +55,16 @@ enum PosixThreadStatus {
}; };
struct PosixThread { struct PosixThread {
void *(*start_routine)(void *);
void *arg; // start_routine's parameter
void *rc; // start_routine's return value
bool ownstack;
int tid;
int *ctid;
char *tls;
char *altstack;
struct CosmoTib *tib;
_Atomic(enum PosixThreadStatus) status; _Atomic(enum PosixThreadStatus) status;
jmp_buf exiter; void *(*start_routine)(void *);
void *arg; // start_routine's parameter
void *rc; // start_routine's return value
bool ownstack; // should we free it
int tid; // clone parent tid
char *altstack; // thread sigaltstack
char *tls; // bottom of tls allocation
struct CosmoTib *tib; // middle of tls allocation
jmp_buf exiter; // for pthread_exit
pthread_attr_t attr; pthread_attr_t attr;
}; };
@ -82,7 +81,7 @@ void _pthread_wait(struct PosixThread *) hidden;
void _pthread_zombies_add(struct PosixThread *) hidden; void _pthread_zombies_add(struct PosixThread *) hidden;
void _pthread_zombies_decimate(void) hidden; void _pthread_zombies_decimate(void) hidden;
void _pthread_zombies_harvest(void) hidden; void _pthread_zombies_harvest(void) hidden;
void _pthread_key_destruct(void *[PTHREAD_KEYS_MAX]); void _pthread_key_destruct(void *[PTHREAD_KEYS_MAX]) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -73,6 +73,9 @@ o/$(MODE)/test/libc/sock/socket_test.com.runs: .INTERNET = 1 # todo: ipv6 filte
o/$(MODE)/test/libc/sock/socket_test.com.runs: \ o/$(MODE)/test/libc/sock/socket_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/test/libc/sock/shutdown_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk $(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
.PHONY: o/$(MODE)/test/libc/sock .PHONY: o/$(MODE)/test/libc/sock