diff --git a/Makefile b/Makefile index 763242b73..f9e65d1b2 100644 --- a/Makefile +++ b/Makefile @@ -148,6 +148,7 @@ include third_party/linenoise/linenoise.mk include third_party/maxmind/maxmind.mk include third_party/lua/lua.mk include third_party/make/make.mk +include third_party/finger/finger.mk include third_party/argon2/argon2.mk include third_party/smallz4/smallz4.mk include third_party/sqlite3/sqlite3.mk diff --git a/libc/dns/getaddrinfo.c b/libc/dns/getaddrinfo.c index f07b10bc6..17da3d03a 100644 --- a/libc/dns/getaddrinfo.c +++ b/libc/dns/getaddrinfo.c @@ -39,7 +39,7 @@ * @param service is the port number as a string * @param hints may be passed to specialize behavior (optional) * @param res receives a pointer that must be freed with freeaddrinfo(), - * and won't be modified if -1 is returned + * and won't be modified if non-zero is returned * @return 0 on success or EAI_xxx value * @threadsafe */ diff --git a/libc/str/bcopy.c b/libc/intrin/bcopy.c similarity index 88% rename from libc/str/bcopy.c rename to libc/intrin/bcopy.c index 2069baa36..121290b57 100644 --- a/libc/str/bcopy.c +++ b/libc/intrin/bcopy.c @@ -1,7 +1,7 @@ /*-*- 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 │ +│ Copyright 2022 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 │ @@ -19,8 +19,10 @@ #include "libc/str/str.h" /** - * Copies memory the legacy way. + * Moves memory the BSD way. + * + * Please use memmove() instead. Note the order of arguments. */ -void *bcopy(void *dst, const void *src, size_t n) { - return memmove(dst, src, n); +void bcopy(const void *src, void *dest, size_t n) { + memmove(dest, src, n); } diff --git a/libc/isystem/utmp.h b/libc/isystem/utmp.h new file mode 100644 index 000000000..bf585f0c3 --- /dev/null +++ b/libc/isystem/utmp.h @@ -0,0 +1,4 @@ +#ifndef COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_ +#define COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_ +#include "libc/runtime/utmp.h" +#endif /* COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_ */ diff --git a/libc/isystem/utmpx.h b/libc/isystem/utmpx.h new file mode 100644 index 000000000..02048d933 --- /dev/null +++ b/libc/isystem/utmpx.h @@ -0,0 +1,4 @@ +#ifndef COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_ +#define COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_ +#include "libc/runtime/utmpx.h" +#endif /* COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_ */ diff --git a/libc/runtime/__utmpxname.S b/libc/runtime/__utmpxname.S new file mode 100644 index 000000000..e8c30b239 --- /dev/null +++ b/libc/runtime/__utmpxname.S @@ -0,0 +1,28 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +__utmpxname: + .errno + mov ENOTSUP(%rip),%edx + mov %edx,(%rax) + ret + .endfn __utmpxname,globl + .alias __utmpxname,utmpname + .alias __utmpxname,utmpxname diff --git a/libc/runtime/utmp.h b/libc/runtime/utmp.h new file mode 100644 index 000000000..2c69a24bb --- /dev/null +++ b/libc/runtime/utmp.h @@ -0,0 +1,47 @@ +#ifndef COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_ +#include "libc/calls/weirdtypes.h" +#include "libc/runtime/utmpx.h" + +#define ACCOUNTING 9 +#define UT_NAMESIZE 32 +#define UT_HOSTSIZE 256 +#define UT_LINESIZE 32 + +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct lastlog { + time_t ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; +}; + +#define ut_time ut_tv.tv_sec +#define ut_name ut_user +#define ut_addr ut_addr_v6[0] +#define utmp utmpx +#define e_exit __e_exit +#define e_termination __e_termination + +int login_tty(int); +int utmpname(const char *); +struct utmp *getutent(void); +struct utmp *getutid(const struct utmp *); +struct utmp *getutline(const struct utmp *); +struct utmp *pututline(const struct utmp *); +void endutent(void); +void setutent(void); +void updwtmp(const char *, const struct utmp *); + +#define _PATH_UTMP "/dev/null/utmp" +#define _PATH_WTMP "/dev/null/wtmp" + +#define UTMP_FILE _PATH_UTMP +#define WTMP_FILE _PATH_WTMP +#define UTMP_FILENAME _PATH_UTMP +#define WTMP_FILENAME _PATH_WTMP + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_ */ diff --git a/libc/runtime/utmpx.h b/libc/runtime/utmpx.h new file mode 100644 index 000000000..78fcb405f --- /dev/null +++ b/libc/runtime/utmpx.h @@ -0,0 +1,51 @@ +#ifndef COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_ +#include "libc/calls/struct/timeval.h" +#include "libc/calls/weirdtypes.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct utmpx { + short ut_type; + pid_t ut_pid; + char ut_line[32]; + char ut_id[4]; + char ut_user[32]; + char ut_host[256]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + long ut_session; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +void endutxent(void); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *); +struct utmpx *getutxline(const struct utmpx *); +struct utmpx *pututxline(const struct utmpx *); +void setutxent(void); + +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define e_exit __e_exit +#define e_termination __e_termination +void updwtmpx(const char *, const struct utmpx *); +int utmpxname(const char *); +#endif + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_ */ diff --git a/libc/sock/connect.c b/libc/sock/connect.c index 71cf4c0c3..4fb1007d7 100644 --- a/libc/sock/connect.c +++ b/libc/sock/connect.c @@ -19,7 +19,9 @@ #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/sock/internal.h" +#include "libc/sock/sock.h" #include "libc/sock/sockdebug.h" #include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/str/str.h b/libc/str/str.h index d91a19ef0..45b708fb3 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -89,6 +89,7 @@ void *memcpy(void *restrict, const void *restrict, size_t) memcpyesque; void *mempcpy(void *restrict, const void *restrict, size_t) memcpyesque; void *memccpy(void *restrict, const void *restrict, int, size_t) memcpyesque; void *memeqmask(void *, const void *, const void *, size_t) memcpyesque; +void bcopy(const void *, void *, size_t) memcpyesque; void explicit_bzero(void *, size_t); int bcmp(const void *, const void *, size_t) strlenesque; diff --git a/libc/stubs/endutxent.S b/libc/stubs/endutxent.S new file mode 100644 index 000000000..4e7389cd3 --- /dev/null +++ b/libc/stubs/endutxent.S @@ -0,0 +1,26 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Closes user accounting database. +// @note unsupported +endutxent: + ret + .endfn endutxent,globl + .alias endutxent,endutent diff --git a/libc/stubs/getutxent.S b/libc/stubs/getutxent.S new file mode 100644 index 000000000..c4bff11ca --- /dev/null +++ b/libc/stubs/getutxent.S @@ -0,0 +1,27 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Reads next entry in user accounting database. +// @note unsupported +getutxent: + xor %eax,%eax + ret + .endfn getutxent,globl + .alias getutxent,getutent diff --git a/libc/stubs/getutxid.S b/libc/stubs/getutxid.S new file mode 100644 index 000000000..53b0870c3 --- /dev/null +++ b/libc/stubs/getutxid.S @@ -0,0 +1,27 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Searches forward in the user accounting database. +// @note unsupported +getutxid: + xor %eax,%eax + ret + .endfn getutxid,globl + .alias getutxid,getutid diff --git a/libc/stubs/getutxline.S b/libc/stubs/getutxline.S new file mode 100644 index 000000000..22f99027c --- /dev/null +++ b/libc/stubs/getutxline.S @@ -0,0 +1,27 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Searches forward in the user accounting database. +// @note unsupported +getutxline: + xor %eax,%eax + ret + .endfn getutxline,globl + .alias getutxline,getutline diff --git a/libc/stubs/pututxline.S b/libc/stubs/pututxline.S new file mode 100644 index 000000000..2dc323b0a --- /dev/null +++ b/libc/stubs/pututxline.S @@ -0,0 +1,27 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Puts in the user accounting database. +// @note unsupported +pututxline: + xor %eax,%eax + ret + .endfn pututxline,globl + .alias pututxline,pututline diff --git a/libc/stubs/setutxent.S b/libc/stubs/setutxent.S new file mode 100644 index 000000000..53d72b071 --- /dev/null +++ b/libc/stubs/setutxent.S @@ -0,0 +1,26 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Rewinds the user accounting database. +// @note unsupported +setutxent: + ret + .endfn setutxent,globl + .alias setutxent,setutent diff --git a/libc/stubs/updwtmpx.S b/libc/stubs/updwtmpx.S new file mode 100644 index 000000000..025a35176 --- /dev/null +++ b/libc/stubs/updwtmpx.S @@ -0,0 +1,26 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 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/macros.internal.h" + +// Does something to the user accounting database. +// @note unsupported +updwtmpx: + ret + .endfn updwtmpx,globl + .alias updwtmpx,updwtmp diff --git a/third_party/finger/display.c b/third_party/finger/display.c new file mode 100644 index 000000000..4a45fb9d0 --- /dev/null +++ b/third_party/finger/display.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/ioctl.h" +#include "libc/calls/struct/termios.h" +#include "libc/calls/struct/winsize.h" +#include "libc/calls/termios.h" +#include "libc/fmt/fmt.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/fileno.h" +#include "libc/sysv/consts/termios.h" +#include "third_party/finger/finger.h" +// clang-format off + +int +getscreenwidth(void) +{ + struct winsize ws; + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col==0) { + return 80; + } + return ws.ws_col; +} + +int +is8bit(void) +{ + static int cache=-1; + struct termios tios; + if (cache>=0) return cache; + + if (tcgetattr(STDIN_FILENO, &tios)<0) { + /* assume 8-bit; it's 1999 now, not 1972 */ + cache = 1; + } + else { + cache = (tios.c_cflag & CSIZE)==CS8; + } + return cache; +} + +/************/ + +static int send_crs=0; + +void +set_crmode(void) +{ + send_crs = 1; +} + +static +void +fxputc(FILE *f, int ch) +{ + /* drop any sign */ + ch = ch&0xff; + + /* on 7-bit terminals, strip high bit */ + if (!is8bit()) ch &= 0x7f; + + /* + * Assume anything that isn't a control character is printable. + * We can't count on locale stuff to tell us what's printable + * because we might be looking at someone who uses different + * locale settings or is on the other side of the planet. So, + * strip 0-31, 127, 128-159, and 255. Note that not stripping + * 128-159 is asking for trouble, as 155 (M-esc) is interpreted + * as esc-[ by most terminals. Hopefully this won't break anyone's + * charset. + * + * It would be nice if we could set the terminal to display in the + * right charset, but we have no way to know what it is. feh. + */ + + if (((ch&0x7f) >= 32 && (ch&0x7f) != 0x7f) || ch=='\t') { + putc(ch, f); + return; + } + + if (ch=='\n') { + if (send_crs) putc('\r', f); + putc('\n', f); + return; + } + + if (ch&0x80) { + putc('M', f); + putc('-', f); + ch &= 0x7f; + } + + putc('^', f); + if (ch==0x7f) putc('?', f); + else putc(ch+'@', f); +} + +void +xputc(int ch) +{ + fxputc(stdout, ch); +} + +static void fxputs(FILE *f, const char *buf) { + int i; + for (i=0; buf[i]; i++) fxputc(f, buf[i]); +} + +int xprintf(const char *fmt, ...) { + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + fxputs(stdout, buf); + + return strlen(buf); +} + +int eprintf(const char *fmt, ...) { + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + fxputs(stderr, buf); + + return strlen(buf); +} diff --git a/third_party/finger/finger.1 b/third_party/finger/finger.1 new file mode 100644 index 000000000..553af0458 --- /dev/null +++ b/third_party/finger/finger.1 @@ -0,0 +1,194 @@ +.\" Copyright (c) 1989, 1990 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. 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. +.\" +.\" from: @(#)finger.1 6.14 (Berkeley) 7/27/91 +.\" $Id: finger.1,v 1.18 2000/07/30 23:56:57 dholland Exp $ +.\" +.Dd August 15, 1999 +.Dt FINGER 1 +.Os "Linux NetKit (0.17)" +.Sh NAME +.Nm finger +.Nd user information lookup program +.Sh SYNOPSIS +.Nm finger +.Op Fl lmsp +.Op Ar user ... +.Op Ar user@host ... +.Sh DESCRIPTION +The +.Nm finger +displays information about the system users. +.Pp +Options are: +.Bl -tag -width flag +.It Fl s +.Nm Finger +displays the user's login name, real name, terminal name and write +status (as a ``*'' after the terminal name if write permission is +denied), idle time, login time, office location and office phone +number. +.Pp +Login time is displayed as month, day, hours and minutes, unless +more than six months ago, in which case the year is displayed rather +than the hours and minutes. +.Pp +Unknown devices as well as nonexistent idle and login times are +displayed as single asterisks. +.Pp +.It Fl l +Produces a multi-line format displaying all of the information +described for the +.Fl s +option as well as the user's home directory, home phone number, login +shell, mail status, and the contents of the files +.Dq Pa .plan , +.Dq Pa .project , +.Dq Pa .pgpkey +and +.Dq Pa .forward +from the user's home directory. +.Pp +Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''. +Numbers specified as ten or seven digits are printed as the appropriate +subset of that string. +Numbers specified as five digits are printed as ``xN-NNNN''. +Numbers specified as four digits are printed as ``xNNNN''. +.Pp +If write permission is denied to the device, the phrase ``(messages off)'' +is appended to the line containing the device name. +One entry per user is displayed with the +.Fl l +option; if a user is logged on multiple times, terminal information +is repeated once per login. +.Pp +Mail status is shown as ``No Mail.'' if there is no mail at all, +``Mail last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked +at their mailbox since new mail arriving, or ``New mail received ...'', +`` Unread since ...'' if they have new mail. +.Pp +.It Fl p +Prevents +the +.Fl l +option of +.Nm finger +from displaying the contents of the +.Dq Pa .plan , +.Dq Pa .project +and +.Dq Pa .pgpkey +files. +.It Fl m +Prevent matching of +.Ar user +names. +.Ar User +is usually a login name; however, matching will also be done on the +users' real names, unless the +.Fl m +option is supplied. +All name matching performed by +.Nm finger +is case insensitive. +.El +.Pp +If no options are specified, +.Nm finger +defaults to the +.Fl l +style output if operands are provided, otherwise to the +.Fl s +style. +Note that some fields may be missing, in either format, if information +is not available for them. +.Pp +If no arguments are specified, +.Nm finger +will print an entry for each user currently logged into the system. +.Pp +.Nm Finger +may be used to look up users on a remote machine. +The format is to specify a +.Ar user +as +.Dq Li user@host , +or +.Dq Li @host , +where the default output +format for the former is the +.Fl l +style, and the default output format for the latter is the +.Fl s +style. +The +.Fl l +option is the only option that may be passed to a remote machine. +.Pp +If standard output is a socket, +.Nm finger +will emit a carriage return (^M) before every linefeed (^J). This is +for processing remote finger requests when invoked by +.Xr fingerd 8 . +.Sh FILES +.Bl -tag -width mmmmmmmmmmmmmmm +.It Pa ~/.nofinger +If finger finds this file in a user's home directory, it will, for +finger requests originating outside the local host, firmly deny the +existence of that user. For this to work, the finger program, as +started by +.Xr fingerd 8 , +must be able to see the +.Pa .nofinger +file. This generally means that the home directory containing the file +must have the other-users-execute bit set (o+w). See +.Xr chmod 1 . +If you use this feature for privacy, please test it with ``finger +@localhost'' before relying on it, just in case. +.It ~/.plan +.It ~/.project +.It ~/.pgp +These files are printed as part of a long-format request. The +.Pa .project +file is limited to one line; the +.Pa .plan +file may be arbitrarily long. +.El +.Sh SEE ALSO +.Xr chfn 1 , +.Xr passwd 1 , +.Xr w 1 , +.Xr who 1 +.Sh HISTORY +The +.Nm finger +command appeared in +.Bx 3.0 . diff --git a/third_party/finger/finger.c b/third_party/finger/finger.c new file mode 100644 index 000000000..486624be1 --- /dev/null +++ b/third_party/finger/finger.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/stat.h" +#include "libc/calls/weirdtypes.h" +#include "libc/fmt/fmt.h" +#include "libc/nt/struct/msg.h" +#include "libc/runtime/utmp.h" +#include "libc/sock/sock.h" +#include "libc/sysv/consts/fileno.h" +#include "libc/time/time.h" +#include "third_party/finger/finger.h" +#include "third_party/getopt/getopt.h" +#include "third_party/musl/passwd.h" +// clang-format off + +/* + * Mail status reporting added 931007 by Luke Mewburn, . + */ + +char copyright[] = + "@(#) Copyright (c) 1989 The Regents of the University of California.\n" + "All rights reserved.\n"; + +/* + * from: @(#)finger.c 5.22 (Berkeley) 6/29/90 + */ +char finger_rcsid[] = \ + "$Id: finger.c,v 1.15 1999/12/18 16:41:51 dholland Exp $"; + +/* + * Finger prints out information about users. It is not portable since + * certain fields (e.g. the full user name, office, and phone numbers) are + * extracted from the gecos field of the passwd file which other UNIXes + * may not have or may use for other things. (This is not really true any + * more, btw.) + * + * There are currently two output formats; the short format is one line + * per user and displays login name, tty, login time, real name, idle time, + * and office location/phone number. The long format gives the same + * information (in a more legible format) as well as home directory, shell, + * mail info, and .plan/.project files. + */ + +static void loginlist(void); +static void userlist(int argc, char *argv[]); + +int lflag, pplan; +static int sflag, mflag; +static int enable_nofinger; + +time_t now; +char tbuf[TBUFLEN]; + +PERSON *phead, *ptail; /* the linked list of all people */ +int entries; /* number of people */ + + +int main(int argc, char *argv[]) { + int ch; + struct sockaddr_in sin; + socklen_t slen = sizeof(sin); + + while ((ch = getopt(argc, argv, "lmps")) != EOF) { + switch(ch) { + case 'l': + lflag = 1; /* long format */ + break; + case 'm': + mflag = 1; /* do exact match of names */ + break; + case 'p': + pplan = 1; /* don't show .plan/.project */ + break; + case 's': + sflag = 1; /* short format */ + break; + case '?': + case 'h': + default: + eprintf("usage: finger [-lmps] [login ...]\n"); + return 1; + } + } + argc -= optind; + argv += optind; + + if (getsockname(STDOUT_FILENO, (struct sockaddr *)&sin, &slen)==0) { + /* + * stdout is a socket. must be a network finger request, + * so emit CRs with our LFs at the ends of lines. + */ + set_crmode(); + + /* + * Also, enable .nofinger processing. + */ + enable_nofinger = 1; + } + + /* + * Also check stdin for nofinger processing, because of older + * fingerds that make stdout a pipe for CRLF handling. + */ + if (getsockname(STDIN_FILENO, (struct sockaddr *)&sin, &slen)==0) { + enable_nofinger = 1; + } + + time(&now); + + setpwent(); + + if (!*argv) { + /* + * Assign explicit "small" format if no names given and -l + * not selected. Force the -s BEFORE we get names so proper + * screening will be done. + */ + if (!lflag) { + sflag = 1; /* if -l not explicit, force -s */ + } + loginlist(); + if (entries == 0) { + xprintf("No one logged on.\n"); + } + } + else { + userlist(argc, argv); + /* + * Assign explicit "large" format if names given and -s not + * explicitly stated. Force the -l AFTER we get names so any + * remote finger attempts specified won't be mishandled. + */ + if (!sflag) + lflag = 1; /* if -s not explicit, force -l */ + } + if (entries != 0) { + if (lflag) lflag_print(); + else sflag_print(); + } + return 0; +} + +/* Returns 1 if .nofinger is found and enable_nofinger is set. */ +static +int +check_nofinger(struct passwd *pw) +{ + if (enable_nofinger) { + char path[PATH_MAX]; + struct stat tripe; + snprintf(path, sizeof(path), "%s/.nofinger", pw->pw_dir); + if (stat(path, &tripe)==0) { + return 1; + } + } + return 0; +} + +static void +loginlist(void) +{ + PERSON *pn; + struct passwd *pw; + struct utmp *uptr; + char name[UT_NAMESIZE + 1]; + + name[UT_NAMESIZE] = '\0'; + + /* + * if (!freopen(_PATH_UTMP, "r", stdin)) { + * fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP); + * exit(2); + * } + */ + setutent(); + while ((uptr = getutent())!=NULL) { + if (!uptr->ut_name[0]) + continue; +#ifdef USER_PROCESS + if (uptr->ut_type != USER_PROCESS) continue; +#endif + if ((pn = find_person(uptr->ut_name)) == NULL) { + memcpy(name, uptr->ut_name, UT_NAMESIZE); + if ((pw = getpwnam(name)) == NULL) + continue; + if (check_nofinger(pw)) + continue; + pn = enter_person(pw); + } + enter_where(uptr, pn); + } + for (pn = phead; lflag && pn != NULL; pn = pn->next) + enter_lastlog(pn); + endutent(); +} + + +static void do_local(int argc, char *argv[], int *used) { + int i; + struct passwd *pw; + + /* + * traverse the list of possible login names and check the login name + * and real name against the name specified by the user. + */ + if (mflag) { + for (i = 0; i < argc; i++) + if (used[i] >= 0 && (pw = getpwnam(argv[i]))) { + if (!check_nofinger(pw)) { + enter_person(pw); + used[i] = 1; + } + } + } else for (pw = getpwent(); pw; pw = getpwent()) + for (i = 0; i < argc; i++) + if (used[i] >= 0 && + (!strcasecmp(pw->pw_name, argv[i]) || + match(pw, argv[i]))) { + if (!check_nofinger(pw)) { + enter_person(pw); + used[i] = 1; + } + } + + /* list errors */ + for (i = 0; i < argc; i++) + if (!used[i]) + (void)eprintf("finger: %s: no such user.\n", argv[i]); + +} + +static void +userlist(int argc, char *argv[]) +{ + int i; + PERSON *pn; + PERSON *nethead, **nettail; + struct utmp *uptr; + int dolocal, *used; + + used = calloc(argc, sizeof(int)); + if (!used) { + eprintf("finger: out of space.\n"); + exit(1); + } + + /* pull out all network requests */ + for (i = 0, dolocal = 0, nettail = &nethead; i < argc; i++) { + if (!strchr(argv[i], '@')) { + dolocal = 1; + continue; + } + pn = palloc(); + *nettail = pn; + nettail = &pn->next; + pn->name = argv[i]; + used[i] = -1; + } + *nettail = NULL; + + if (dolocal) do_local(argc, argv, used); + + /* handle network requests */ + for (pn = nethead; pn; pn = pn->next) { + netfinger(pn->name); + if (pn->next || entries) + xputc('\n'); + } + + if (entries == 0) + return; + + /* + * Scan thru the list of users currently logged in, saving + * appropriate data whenever a match occurs. + */ + /* + * if (!freopen(_PATH_UTMP, "r", stdin)) { + * (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP); + * exit(1); + * } + */ + setutent(); + while ((uptr = getutent())!=NULL) { + if (!uptr->ut_name[0]) + continue; +#ifdef USER_PROCESS + if (uptr->ut_type != USER_PROCESS) continue; +#endif + if ((pn = find_person(uptr->ut_name)) == NULL) { + continue; + } + enter_where(uptr, pn); + } + for (pn = phead; pn != NULL; pn = pn->next) { + enter_lastlog(pn); + } + endutent(); +} diff --git a/third_party/finger/finger.h b/third_party/finger/finger.h new file mode 100644 index 000000000..5bb17aa02 --- /dev/null +++ b/third_party/finger/finger.h @@ -0,0 +1,121 @@ +// clang-format off +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * from: @(#)finger.h 5.5 (Berkeley) 6/1/90 + * $Id: finger.h,v 1.7 1999/09/14 10:51:11 dholland Exp $ + */ +#include "third_party/musl/passwd.h" +#include "libc/runtime/utmp.h" +#include "libc/calls/weirdtypes.h" + +/* + * All unique persons are linked in a list headed by "head" and linkd + * by the "next" field, as well as kept in a hash table. + */ + +typedef struct person { + struct person *next; /* link to next person */ + struct person *hlink; /* link to next person in hash bucket */ + uid_t uid; /* user id */ + char *dir; /* user's home directory */ + char *homephone; /* pointer to home phone no. */ + char *name; /* login name */ + char *office; /* pointer to office name */ + char *officephone; /* pointer to office phone no. */ + char *realname; /* pointer to full name */ + char *shell; /* user's shell */ + time_t mailread; /* last time mail was read */ + time_t mailrecv; /* last time mail was read */ + struct where *whead, *wtail; /* list of where he is or has been */ +} PERSON; + +enum status { LASTLOG, LOGGEDIN }; + +typedef struct where { + struct where *next; /* next place he is or has been */ + enum status info; /* type/status of request */ + short writable; /* tty is writable */ + time_t loginat; /* time of (last) login */ + time_t idletime; /* how long idle (if logged in) */ + char tty[UT_LINESIZE+1]; /* null terminated tty line */ + char host[UT_HOSTSIZE+1]; /* null terminated remote host name */ +} WHERE; + +extern PERSON *phead, *ptail; /* the linked list of all people */ + +extern int entries; /* number of people */ + +#define TBUFLEN 1024 +extern char tbuf[TBUFLEN]; /* temp buffer for anybody */ + +extern time_t now; +extern int lflag, pplan; + +struct utmp; +PERSON *enter_person(struct passwd *); +PERSON *find_person(const char *name); +PERSON *palloc(void); +WHERE *walloc(PERSON *); +void lflag_print(void); +void sflag_print(void); +void enter_where(struct utmp *ut, PERSON *pn); +void enter_lastlog(PERSON *pn); +int match(struct passwd *pw, const char *user); +void netfinger(const char *name); +const char *prphone(const char *num); + +#ifndef DAYSPERNYEAR +#define DAYSPERNYEAR 365 +#endif + +#ifndef SECSPERDAY +#define SECSPERDAY (60 * 60 * 24) +#endif + +/* turn on crnl translation on output */ +void set_crmode(void); + +/* Display, masking control characters and possibly doing crnl translation */ +void xputc(int ch); +void xputs(const char *buf); +int xprintf(const char *fmt, ...); + +/* Send to stderr, possibly doing crnl translation */ +int eprintf(const char *fmt, ...); + +/* terminal inquiries */ +int is8bit(void); +int getscreenwidth(void); diff --git a/third_party/finger/finger.mk b/third_party/finger/finger.mk new file mode 100644 index 000000000..9910d2cca --- /dev/null +++ b/third_party/finger/finger.mk @@ -0,0 +1,68 @@ +#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ +#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ + +PKGS += THIRD_PARTY_FINGER + +THIRD_PARTY_FINGER_ARTIFACTS += THIRD_PARTY_FINGER_A +THIRD_PARTY_FINGER = $(THIRD_PARTY_FINGER_A_DEPS) $(THIRD_PARTY_FINGER_A) +THIRD_PARTY_FINGER_A = o/$(MODE)/third_party/finger/finger.a +THIRD_PARTY_FINGER_A_FILES := $(wildcard third_party/finger/*) +THIRD_PARTY_FINGER_A_HDRS = $(filter %.h,$(THIRD_PARTY_FINGER_A_FILES)) +THIRD_PARTY_FINGER_A_INCS = $(filter %.inc,$(THIRD_PARTY_FINGER_A_FILES)) +THIRD_PARTY_FINGER_A_SRCS = $(filter %.c,$(THIRD_PARTY_FINGER_A_FILES)) +THIRD_PARTY_FINGER_A_OBJS = $(THIRD_PARTY_FINGER_A_SRCS:%.c=o/$(MODE)/%.o) + +THIRD_PARTY_FINGER_A_DIRECTDEPS = \ + LIBC_CALLS \ + LIBC_FMT \ + LIBC_INTRIN \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_RUNTIME \ + LIBC_STDIO \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_SYSV \ + LIBC_DNS \ + LIBC_SOCK \ + LIBC_TIME \ + LIBC_UNICODE \ + THIRD_PARTY_MUSL \ + THIRD_PARTY_GETOPT + +THIRD_PARTY_FINGER_A_DEPS := \ + $(call uniq,$(foreach x,$(THIRD_PARTY_FINGER_A_DIRECTDEPS),$($(x)))) + +THIRD_PARTY_FINGER_A_CHECKS = \ + $(THIRD_PARTY_FINGER_A).pkg + +$(THIRD_PARTY_FINGER_A): \ + third_party/finger/ \ + $(THIRD_PARTY_FINGER_A).pkg \ + $(THIRD_PARTY_FINGER_A_OBJS) + +$(THIRD_PARTY_FINGER_A).pkg: \ + $(THIRD_PARTY_FINGER_A_OBJS) \ + $(foreach x,$(THIRD_PARTY_FINGER_A_DIRECTDEPS),$($(x)_A).pkg) + +o/$(MODE)/third_party/finger/finger.com.dbg: \ + $(THIRD_PARTY_FINGER) \ + o/$(MODE)/third_party/finger/finger.o \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +THIRD_PARTY_FINGER_COMS = o/$(MODE)/third_party/finger/finger.com +THIRD_PARTY_FINGER_BINS = $(THIRD_PARTY_FINGER_COMS) $(THIRD_PARTY_FINGER_COMS:%=%.dbg) +THIRD_PARTY_FINGER_LIBS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x))) +THIRD_PARTY_FINGER_SRCS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x)_SRCS)) +THIRD_PARTY_FINGER_HDRS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_FINGER_INCS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x)_INCS)) +THIRD_PARTY_FINGER_CHECKS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x)_CHECKS)) +THIRD_PARTY_FINGER_OBJS = $(foreach x,$(THIRD_PARTY_FINGER_ARTIFACTS),$($(x)_OBJS)) +$(THIRD_PARTY_FINGER_OBJS): third_party/finger/finger.mk + +.PHONY: o/$(MODE)/third_party/finger +o/$(MODE)/third_party/finger: \ + $(THIRD_PARTY_FINGER_BINS) \ + $(THIRD_PARTY_FINGER_CHECKS) diff --git a/third_party/finger/lprint.c b/third_party/finger/lprint.c new file mode 100644 index 000000000..f5bc2f0ed --- /dev/null +++ b/third_party/finger/lprint.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/stat.h" +#include "libc/fmt/fmt.h" +#include "libc/paths.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/s.h" +#include "libc/time/time.h" +#include "third_party/finger/finger.h" +// clang-format off + +/* + * from: @(#)lprint.c 5.13 (Berkeley) 10/31/90 + */ +char lprint_rcsid[] = + "$Id: lprint.c,v 1.11 1999/09/14 10:51:11 dholland Exp $"; + +static void lprint(PERSON *pn); +static int demi_print(char *str, int oddfield); +static int show_text(const char *directory, const char *file_name, + const char *header); + +#define LINE_LEN 80 +#define TAB_LEN 8 /* 8 spaces between tabs */ +#define _PATH_FORWARD ".forward" +#define _PATH_PLAN ".plan" +#define _PATH_PROJECT ".project" +#define _PATH_PGPKEY ".pgpkey" + +void +lflag_print(void) +{ + register PERSON *pn = phead; + while (1) { + lprint(pn); + if (!pplan) { + show_text(pn->dir, _PATH_PGPKEY, "PGP key:\n"); + show_text(pn->dir, _PATH_PROJECT, "Project:\n"); + if (!show_text(pn->dir, _PATH_PLAN, "Plan:\n")) { + xprintf("No Plan.\n"); + } + } + if (!(pn = pn->next)) + break; + xputc('\n'); + } +} + +static void +lprint(PERSON *pn) +{ + struct tm *delta, *tp; + WHERE *w; + int cpr, len, maxlen; + int oddfield; + char timebuf[128]; + + /* + * long format -- + * login name + * real name + * home directory + * shell + * office, office phone, home phone if available + */ + xprintf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", + pn->name, pn->realname, pn->dir); + xprintf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); + + /* + * try and print office, office phone, and home phone on one line; + * if that fails, do line filling so it looks nice. + */ +#define OFFICE_TAG "Office" +#define OFFICE_PHONE_TAG "Office Phone" + oddfield = 0; + if (pn->office && pn->officephone && + strlen(pn->office) + strlen(pn->officephone) + + sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) + { + snprintf(tbuf, TBUFLEN, "%s: %s, %s", OFFICE_TAG, pn->office, + prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } + else { + if (pn->office) { + snprintf(tbuf, TBUFLEN, "%s: %s", OFFICE_TAG, + pn->office); + oddfield = demi_print(tbuf, oddfield); + } + if (pn->officephone) { + snprintf(tbuf, TBUFLEN, "%s: %s", OFFICE_PHONE_TAG, + prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } + } + if (pn->homephone) { + snprintf(tbuf, TBUFLEN, "%s: %s", "Home Phone", + prphone(pn->homephone)); + oddfield = demi_print(tbuf, oddfield); + } + if (oddfield) xputc('\n'); + + /* + * long format con't: * if logged in + * terminal + * idle time + * if messages allowed + * where logged in from + * if not logged in + * when last logged in + */ + /* find out longest device name for this user for formatting */ + for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) + if ((len = strlen(w->tty)) > maxlen) + maxlen = len; + /* find rest of entries for user */ + for (w = pn->whead; w != NULL; w = w->next) { + switch (w->info) { + case LOGGEDIN: + tp = localtime(&w->loginat); + /* + * t = asctime(tp); + * tzset(); + * tzn = tzname[daylight]; + * cpr = printf("On since %.16s (%s) on %s", + * t, tzn, w->tty); + */ + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R (%Z)", tp); + cpr = xprintf("On since %s on %s", timebuf, w->tty); + if (*w->host) { + cpr += xprintf(" from %s", w->host); + } + /* + * idle time is tough; if have one, print a comma, + * then spaces to pad out the device name, then the + * idle time. Follow with a comma if a remote login. + */ + delta = gmtime(&w->idletime); + if (delta->tm_yday || delta->tm_hour + || delta->tm_min || delta->tm_sec) { + if (*w->host) + xputc('\n'); + cpr += xprintf("%-*s", + (int) (maxlen - strlen(w->tty) + 3), ""); + if (delta->tm_yday > 0) { + cpr += xprintf("%d day%s ", + delta->tm_yday, + delta->tm_yday == 1 ? "" : "s"); + } + if (delta->tm_hour > 0) { + cpr += xprintf("%d hour%s ", + delta->tm_hour, + delta->tm_hour == 1 ? "" : "s"); + } + if ((delta->tm_min > 0) && !delta->tm_yday) { + cpr += xprintf("%d minute%s ", + delta->tm_min, + delta->tm_min == 1 ? "" : "s"); + } + if ((delta->tm_sec > 0) && !delta->tm_yday + && !delta->tm_hour) { + cpr += xprintf("%d second%s ", + delta->tm_sec, + delta->tm_sec == 1 ? "" : "s"); + } + cpr += xprintf("idle"); + } + if (!w->writable) { + if (delta->tm_yday || delta->tm_hour + || delta->tm_min || delta->tm_sec) + cpr += xprintf("\n "); + cpr += xprintf(" (messages off)"); + } + break; + case LASTLOG: + if (w->loginat == 0) { + (void)xprintf("Never logged in."); + break; + } + tp = localtime(&w->loginat); + /* + * t = asctime(tp); + * tzset(); + * tzn = tzname[daylight]; + * if(now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2) + * cpr = + * printf("Last login %.16s %.4s (%s) on %s", + * t, t + 20, tzn, w->tty); + * else + * cpr = printf("Last login %.16s (%s) on %s", + * t, tzn, w->tty); + */ + if (now - w->loginat < SECSPERDAY * DAYSPERNYEAR / 2) { + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R (%Z)", tp); + } + else { + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R %Y (%Z)", tp); + } + cpr = xprintf("Last login %s on %s", timebuf, w->tty); + if (*w->host) { + cpr += xprintf(" from %s", w->host); + } + break; + } + xputc('\n'); + } + + /* If the user forwards mail elsewhere, tell us about it */ + show_text(pn->dir, _PATH_FORWARD, "Mail forwarded to "); + + /* Print the standard mailbox information. */ + if (pn->mailrecv == -1) + xprintf("No mail.\n"); + else if (pn->mailrecv > pn->mailread) { + tp = localtime(&pn->mailrecv); + /* + * t = asctime(tp); + * tzset(); + * tzn = tzname[daylight]; + * printf("New mail received %.16s %.4s (%s)\n", t, + * t + 20, tzn); + */ + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R %Y (%Z)", tp); + xprintf("New mail received %s\n", timebuf); + tp = localtime(&pn->mailread); + /* + * t = asctime(tp); + * tzset(); + * tzn = tzname[daylight]; + * printf(" Unread since %.16s %.4s (%s)\n", t, + * t + 20, tzn); + */ + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R %Y (%Z)", tp); + xprintf(" Unread since %s\n", timebuf); + } else { + tp = localtime(&pn->mailread); + /* + * t = asctime(tp); + * tzset(); + * tzn = tzname[daylight]; + * printf("Mail last read %.16s %.4s (%s)\n", t, + * t + 20, tzn); + */ + strftime(timebuf, sizeof(timebuf), + "%a %b %e %R %Y (%Z)", tp); + xprintf("Mail last read %s\n", timebuf); + } +} + +static int +demi_print(char *str, int oddfield) +{ + static int lenlast; + int lenthis, maxlen; + + lenthis = strlen(str); + if (oddfield) { + /* + * We left off on an odd number of fields. If we haven't + * crossed the midpoint of the screen, and we have room for + * the next field, print it on the same line; otherwise, + * print it on a new line. + * + * Note: we insist on having the right hand fields start + * no less than 5 tabs out. + */ + maxlen = 5 * TAB_LEN; + if (maxlen < lenlast) + maxlen = lenlast; + if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + + lenthis) <= LINE_LEN) { + while(lenlast < (4 * TAB_LEN)) { + xputc('\t'); + lenlast += TAB_LEN; + } + (void)xprintf("\t%s\n", str); /* force one tab */ + } else { + (void)xprintf("\n%s", str); /* go to next line */ + oddfield = !oddfield; /* this'll be undone below */ + } + } else + (void)xprintf("%s", str); + oddfield = !oddfield; /* toggle odd/even marker */ + lenlast = lenthis; + return(oddfield); +} + +static int +show_text(const char *directory, const char *file_name, const char *header) +{ + int ch, lastc = 0, fd; + FILE *fp; + struct stat sbuf1, sbuf2; + + snprintf(tbuf, TBUFLEN, "%s/%s", directory, file_name); + + if (lstat(tbuf, &sbuf1) || !S_ISREG(sbuf1.st_mode)) return 0; + fd = open(tbuf, O_RDONLY); + if (fd<0) return 0; + if (fstat(fd, &sbuf2)) { close(fd); return 0; } + /* if we didn't get the same file both times, bail */ + if (sbuf1.st_dev!=sbuf2.st_dev || sbuf1.st_ino!=sbuf2.st_ino) { + close(fd); + return 0; + } + fp = fdopen(fd, "r"); + if (fp == NULL) { close(fd); return 0; } + + xprintf("%s", header); + while ((ch = getc(fp)) != EOF) { + xputc(ch); + lastc = ch; + } + if (lastc != '\n') xputc('\n'); + + fclose(fp); + return 1; +} + diff --git a/third_party/finger/net.c b/third_party/finger/net.c new file mode 100644 index 000000000..ead55d7f2 --- /dev/null +++ b/third_party/finger/net.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/ent.h" +#include "libc/errno.h" +#include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/sock.h" +#include "third_party/finger/finger.h" +// clang-format off + +#ifndef lint +/*static char sccsid[] = "from: @(#)net.c 5.5 (Berkeley) 6/1/90";*/ +char net_rcsid[] = "$Id: net.c,v 1.9 1999/09/14 10:51:11 dholland Exp $"; +#endif /* not lint */ + +void netfinger(const char *name) { + register FILE *fp; + struct in_addr defaddr; + register int c, sawret, ateol; + struct hostent *hp, def; + struct servent *sp; + struct sockaddr_in sn; + int s; + char *alist[1], *host; + + host = strrchr(name, '@'); + if (!host) return; + *host++ = '\0'; + + memset(&sn, 0, sizeof(sn)); + + sp = getservbyname("finger", "tcp"); + if (!sp) { + eprintf("finger: tcp/finger: unknown service\n"); + return; + } + sn.sin_port = sp->s_port; + + hp = gethostbyname(host); + if (!hp) { + if (!inet_aton(host, &defaddr)) { + eprintf("finger: unknown host: %s\n", host); + return; + } + def.h_name = host; + def.h_addr_list = alist; + def.h_addr = (char *)&defaddr; + def.h_length = sizeof(struct in_addr); + def.h_addrtype = AF_INET; + def.h_aliases = 0; + hp = &def; + } + sn.sin_family = hp->h_addrtype; + if (hp->h_length > (int)sizeof(sn.sin_addr)) { + hp->h_length = sizeof(sn.sin_addr); + } + memcpy(&sn.sin_addr, hp->h_addr, hp->h_length); + + if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + eprintf("finger: socket: %s\n", strerror(errno)); + return; + } + + /* print hostname before connecting, in case it takes a while */ + xprintf("[%s]\n", hp->h_name); + if (connect(s, (struct sockaddr *)&sn, sizeof(sn)) < 0) { + eprintf("finger: connect: %s\n", strerror(errno)); + close(s); + return; + } + + /* -l flag for remote fingerd */ + if (lflag) write(s, "/W ", 3); + + /* send the name followed by */ + write(s, name, strlen(name)); + write(s, "\r\n", 2); + + /* + * Read from the remote system; once we're connected, we assume some + * data. If none arrives, we hang until the user interrupts. + * + * If we see a or a with the high bit set, treat it as + * a newline; if followed by a newline character, only output one + * newline. + * + * Text is sent to xputc() for printability analysis. + */ + fp = fdopen(s, "r"); + if (!fp) { + eprintf("finger: fdopen: %s\n", strerror(errno)); + close(s); + return; + } + + sawret = 0; + ateol = 1; + while ((c = getc(fp)) != EOF) { + c &= 0xff; + if (c == ('\r'|0x80) || c == ('\n'|0x80)) c &= 0x7f; + if (c == '\r') { + sawret = ateol = 1; + xputc('\n'); + } + else if (sawret && c == '\n') { + sawret = 0; + /* don't print */ + } + else { + if (c == '\n') ateol = 1; + sawret = 0; + xputc(c); + } + } + if (!ateol) xputc('\n'); + fclose(fp); +} diff --git a/third_party/finger/sprint.c b/third_party/finger/sprint.c new file mode 100644 index 000000000..1f5c1c6f0 --- /dev/null +++ b/third_party/finger/sprint.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/alg/alg.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/time/time.h" +#include "third_party/finger/finger.h" +// clang-format off + +#ifndef lint +/*static char sccsid[] = "from: @(#)sprint.c 5.8 (Berkeley) 12/4/90";*/ +char sprint_rcsid[] = "$Id: sprint.c,v 1.10 1999/12/12 18:59:33 dholland Exp $"; +#endif /* not lint */ + +static void stimeprint(WHERE *w); +static int psort(const void *a, const void *b); +static PERSON **sort(void); + +void sflag_print(void) { + register PERSON *pn; + register WHERE *w; + register char *p; + PERSON **list; + int maxlname, maxrname, space, cnt; + + list = sort(); + /* + * short format -- + * login name + * real name + * terminal name + * if terminal writeable (add an '*' to the terminal name + * if not) + * if logged in show idle time and day logged in, else + * show last login date and time. If > 6 moths, + * show year instead of time. + * office location + * office phone + */ + + maxlname = maxrname = sizeof("Login "); + for (cnt = 0; cnt < entries; ++cnt) { + int l; + pn = list[cnt]; + l = pn->name ? strlen(pn->name) : 1; + if (l > maxlname) maxlname = l; + l = pn->realname ? strlen(pn->realname) : 1; + if (l > maxrname) maxrname = l; + } + /* prevent screen overflow */ + space = getscreenwidth() - 50; + if (maxlname + maxrname > space) maxrname = space - maxlname; + + /* add a space if there's room */ + if (maxlname + maxrname < space-2) { maxlname++; maxrname++; } + + (void)xprintf("%-*s %-*s %s\n", maxlname, "Login", maxrname, + "Name", " Tty Idle Login Time Office Office Phone"); + for (cnt = 0; cnt < entries; ++cnt) { + pn = list[cnt]; + for (w = pn->whead; w != NULL; w = w->next) { + (void)xprintf("%-*.*s %-*.*s ", maxlname, maxlname, + pn->name, maxrname, maxrname, + pn->realname ? pn->realname : ""); + if (!w->loginat) { + (void)xprintf(" * * No logins "); + goto office; + } + (void)xputc(w->info == LOGGEDIN && !w->writable ? + '*' : ' '); + if (*w->tty) + (void)xprintf("%-7.7s ", w->tty); + else + (void)xprintf(" "); + if (w->info == LOGGEDIN) { + stimeprint(w); + (void)xprintf(" "); + } else + (void)xprintf(" * "); + p = ctime(&w->loginat); + (void)xprintf("%.6s", p + 4); + if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2) + (void)xprintf(" %.4s", p + 20); + else + (void)xprintf(" %.5s", p + 11); +office: + if (w->host[0] != '\0') { + xprintf(" (%s)", w->host); + } else { + if (pn->office) + (void)xprintf(" %-10.10s", pn->office); + else if (pn->officephone) + (void)xprintf(" %-10.10s", " "); + if (pn->officephone) + (void)xprintf(" %-.14s", + prphone(pn->officephone)); + } + xputc('\n'); + } + } +} + +static PERSON **sort(void) { + register PERSON *pn, **lp; + PERSON **list; + + if (!(list = (PERSON **)malloc((unsigned)(entries * sizeof(PERSON *))))) { + eprintf("finger: Out of space.\n"); + exit(1); + } + for (lp = list, pn = phead; pn != NULL; pn = pn->next) + *lp++ = pn; + (void)qsort(list, entries, sizeof(PERSON *), psort); + return(list); +} + +static int psort(const void *a, const void *b) { + const PERSON *const *p = (const PERSON *const *)a; + const PERSON *const *t = (const PERSON *const *)b; + return(strcmp((*p)->name, (*t)->name)); +} + +static void stimeprint(WHERE *w) { + register struct tm *delta; + + delta = gmtime(&w->idletime); + if (!delta->tm_yday) + if (!delta->tm_hour) + if (!delta->tm_min) + (void)xprintf(" "); + else + (void)xprintf("%5d", delta->tm_min); + else + (void)xprintf("%2d:%02d", + delta->tm_hour, delta->tm_min); + else + (void)xprintf("%4dd", delta->tm_yday); +} diff --git a/third_party/finger/util.c b/third_party/finger/util.c new file mode 100644 index 000000000..b931e7f8a --- /dev/null +++ b/third_party/finger/util.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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/stat.h" +#include "libc/calls/struct/stat.macros.h" +#include "libc/errno.h" +#include "libc/fmt/fmt.h" +#include "libc/paths.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" +#include "third_party/finger/finger.h" +// clang-format off + +#ifndef lint +/*static char sccsid[] = "from: @(#)util.c 5.14 (Berkeley) 1/17/91";*/ +char util_rcsid[] = "$Id: util.c,v 1.18 1999/09/28 22:53:58 netbug Exp $"; +#endif /* not lint */ + +#define HBITS 8 /* number of bits in hash code */ +#define HSIZE (1 << 8) /* hash table size */ +#define HMASK (HSIZE - 1) /* hash code mask */ +static PERSON *htab[HSIZE]; /* the buckets */ + +static int hash(const char *name); + +static void find_idle_and_ttywrite(register WHERE *w) { + struct stat sb; + + /* No device for X console. Utmp entry by XDM login (":0"). */ + if (w->tty[0] == ':') { + w->idletime = 0; /* would be nice to have it emit ??? */ + w->writable = 0; + return; + } + snprintf(tbuf, TBUFLEN, "%s/%s", _PATH_DEV, w->tty); + if (stat(tbuf, &sb) < 0) { + eprintf("finger: %s: %s\n", tbuf, strerror(errno)); + return; + } + w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; + +#define TALKABLE 0220 /* tty is writable if 220 mode */ + w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); +} + +static void userinfo(PERSON *pn, struct passwd *pw) { + char *p; + struct stat sb; + char *bp; + char *rname; + int i, j, ct; + char *fields[4]; + int nfields; + + pn->uid = pw->pw_uid; + pn->name = strdup(pw->pw_name); + pn->dir = strdup(pw->pw_dir); + pn->shell = strdup(pw->pw_shell); + + /* make a private copy of gecos to munge */ + strncpy(tbuf, pw->pw_gecos, TBUFLEN); + tbuf[TBUFLEN-1] = 0; /* ensure null termination */ + bp = tbuf; + + /* why do we skip asterisks!?!? */ + if (*bp == '*') ++bp; + + /* + * fields[0] -> real name + * fields[1] -> office + * fields[2] -> officephone + * fields[3] -> homephone + */ + nfields = 0; + for (p = strtok(bp, ","); p; p = strtok(NULL, ",")) { + if (*p==0) p = NULL; // skip empties + if (nfields < 4) fields[nfields++] = p; + } + while (nfields<4) fields[nfields++] = NULL; + + if (fields[0]) { + /* + * Ampersands in gecos get replaced by the capitalized login + * name. This is a major nuisance and whoever thought it up + * should be shot. + */ + p = fields[0]; + + /* First, count the number of ampersands. */ + for (ct=i=0; p[i]; i++) if (p[i]=='&') ct++; + + /* This tells us how much space we need to copy the name. */ + rname = malloc(strlen(p) + ct*strlen(pw->pw_name) + 1); + if (!rname) { + eprintf("finger: Out of space.\n"); + exit(1); + } + + /* Now, do it */ + for (i=j=0; p[i]; i++) { + if (p[i]=='&') { + strcpy(rname + j, pw->pw_name); + if (islower(rname[j])) { + rname[j] = toupper(rname[j]); + } + j += strlen(pw->pw_name); + } + else { + rname[j++] = p[i]; + } + } + rname[j] = 0; + + pn->realname = rname; + } + + pn->office = fields[1] ? strdup(fields[1]) : NULL; + pn->officephone = fields[2] ? strdup(fields[2]) : NULL; + pn->homephone = fields[3] ? strdup(fields[3]) : NULL; + + pn->mailrecv = -1; /* -1 == not_valid */ + pn->mailread = -1; /* -1 == not_valid */ + + snprintf(tbuf, TBUFLEN, "%s/%s", _PATH_MAILDIR, pw->pw_name); + if (stat(tbuf, &sb) < 0) { + if (errno != ENOENT) { + eprintf("finger: %s: %s\n", tbuf, strerror(errno)); + return; + } + } + else if (sb.st_size != 0) { + pn->mailrecv = sb.st_mtime; + pn->mailread = sb.st_atime; + } +} + +int +match(struct passwd *pw, const char *user) +{ + char *p; + int i, j, ct, rv=0; + char *rname; + + strncpy(tbuf, pw->pw_gecos, TBUFLEN); + tbuf[TBUFLEN-1] = 0; /* guarantee null termination */ + p = tbuf; + + /* why do we skip asterisks!?!? */ + if (*p == '*') ++p; + + /* truncate the uninteresting stuff off the end of gecos */ + p = strtok(p, ","); + if (!p) return 0; + + /* + * Ampersands get replaced by the login name. + */ + + /* First, count the number of ampersands. */ + for (ct=i=0; p[i]; i++) if (p[i]=='&') ct++; + + /* This tells us how much space we need to copy the name. */ + rname = malloc(strlen(p) + ct*strlen(pw->pw_name) + 1); + if (!rname) { + eprintf("finger: Out of space.\n"); + exit(1); + } + + /* Now, do it */ + for (i=j=0; p[i]; i++) { + if (p[i]=='&') { + strcpy(rname + j, pw->pw_name); + if (islower(rname[j])) rname[j] = toupper(rname[j]); + j += strlen(pw->pw_name); + } + else { + rname[j++] = p[i]; + } + } + rname[j] = 0; + + for (p = strtok(rname, "\t "); p && !rv; p = strtok(NULL, "\t ")) { + if (!strcasecmp(p, user)) + rv = 1; + } + free(rname); + + return rv; +} + +static int get_lastlog(int fd, uid_t uid, struct lastlog *ll) { + loff_t pos; + if (fd == -1) return -1; + pos = (long)uid * sizeof(*ll); + if (lseek(fd, pos, SEEK_SET) != pos) return -1; + if (read(fd, ll, sizeof(*ll)) != sizeof(*ll)) return -1; + return 0; +} + +void enter_lastlog(PERSON *pn) { + static int opened = 0, fd = -1; + + WHERE *w; + struct lastlog ll; + int doit = 0; + + /* some systems may not maintain lastlog, don't report errors. */ + if (!opened) { + fd = open(_PATH_LASTLOG, O_RDONLY, 0); + opened = 1; + } + if (get_lastlog(fd, pn->uid, &ll)) { + /* as if never logged in */ + ll.ll_line[0] = ll.ll_host[0] = '\0'; + ll.ll_time = 0; + } + + if ((w = pn->whead) == NULL) + doit = 1; + else if (ll.ll_time != 0) { + /* if last login is earlier than some current login */ + for (; !doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && w->loginat < ll.ll_time) + doit = 1; + /* + * and if it's not any of the current logins + * can't use time comparison because there may be a small + * discrepency since login calls time() twice + */ + for (w = pn->whead; doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && + strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) + doit = 0; + } + if (doit) { + w = walloc(pn); + w->info = LASTLOG; + bcopy(ll.ll_line, w->tty, UT_LINESIZE); + w->tty[UT_LINESIZE] = 0; + bcopy(ll.ll_host, w->host, UT_HOSTSIZE); + w->host[UT_HOSTSIZE] = 0; + w->loginat = ll.ll_time; + } +} + +void enter_where(struct utmp *ut, PERSON *pn) { + register WHERE *w = walloc(pn); + + w->info = LOGGEDIN; + bcopy(ut->ut_line, w->tty, UT_LINESIZE); + w->tty[UT_LINESIZE] = 0; + bcopy(ut->ut_host, w->host, UT_HOSTSIZE); + w->host[UT_HOSTSIZE] = 0; + w->loginat = ut->ut_time; + find_idle_and_ttywrite(w); +} + +PERSON * enter_person(struct passwd *pw) { + register PERSON *pn, **pp; + + for (pp = htab + hash(pw->pw_name); + *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0; + pp = &(*pp)->hlink) + ; + if ((pn = *pp) == NULL) { + pn = palloc(); + entries++; + if (phead == NULL) + phead = ptail = pn; + else { + ptail->next = pn; + ptail = pn; + } + pn->next = NULL; + pn->hlink = NULL; + *pp = pn; + userinfo(pn, pw); + pn->whead = NULL; + } + return(pn); +} + +PERSON *find_person(const char *name) { + register PERSON *pn; + + /* name may be only UT_NAMESIZE long and not terminated */ + for (pn = htab[hash(name)]; + pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0; + pn = pn->hlink) + ; + return(pn); +} + +static int hash(const char *name) { + register int h, i; + + h = 0; + /* name may be only UT_NAMESIZE long and not terminated */ + for (i = UT_NAMESIZE; --i >= 0 && *name;) + h = ((h << 2 | h >> (HBITS - 2)) ^ *name++) & HMASK; + return(h); +} + +PERSON *palloc(void) { + PERSON *p; + + if ((p = (PERSON *)malloc((unsigned) sizeof(PERSON))) == NULL) { + eprintf("finger: Out of space.\n"); + exit(1); + } + return(p); +} + +WHERE * +walloc(PERSON *pn) +{ + register WHERE *w; + + if ((w = (WHERE *)malloc((unsigned) sizeof(WHERE))) == NULL) { + eprintf("finger: Out of space.\n"); + exit(1); + } + if (pn->whead == NULL) + pn->whead = pn->wtail = w; + else { + pn->wtail->next = w; + pn->wtail = w; + } + w->next = NULL; + return(w); +} + +const char * +prphone(const char *num) +{ + char *p; + const char *q; + int len; + static char pbuf[15]; + + /* don't touch anything if the user has their own formatting */ + for (q = num; *q; ++q) + if (!isdigit(*q)) + return(num); + len = q - num; + p = pbuf; + switch(len) { + case 11: /* +0-123-456-7890 */ + *p++ = '+'; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 10: /* 012-345-6789 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 7: /* 012-3456 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + break; + case 5: /* x0-1234 */ + case 4: /* x1234 */ + *p++ = 'x'; + *p++ = *num++; + break; + default: + return num; + } + if (len != 4) { + *p++ = '-'; + *p++ = *num++; + } + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p = '\0'; + return(pbuf); +} diff --git a/third_party/lua/lunix.c b/third_party/lua/lunix.c index 497b8c286..a558627b7 100644 --- a/third_party/lua/lunix.c +++ b/third_party/lua/lunix.c @@ -101,12 +101,6 @@ struct UnixErrno { const char *call; }; -union SockAddr { - struct sockaddr s; - struct sockaddr_in i; - struct sockaddr_un u; -}; - static lua_State *GL; static void *LuaRealloc(lua_State *L, void *p, size_t n) { @@ -225,23 +219,26 @@ static int SysretInteger(lua_State *L, const char *call, int olderr, } } -static int MakeSockaddr(lua_State *L, int i, union SockAddr *sa, +static int MakeSockaddr(lua_State *L, int i, struct sockaddr_storage *ss, uint32_t *salen) { - bzero(sa, sizeof(*sa)); - if (lua_isstring(L, i)) { - sa->u.sun_family = AF_UNIX; - if (!memccpy(sa->u.sun_path, luaL_checkstring(L, i), 0, - sizeof(sa->u.sun_path))) { + bzero(ss, sizeof(*ss)); + if (!lua_isinteger(L, i)) { + ((struct sockaddr_un *)ss)->sun_family = AF_UNIX; + if (!memccpy(((struct sockaddr_un *)ss)->sun_path, luaL_checkstring(L, i), + 0, sizeof(((struct sockaddr_un *)ss)->sun_path))) { luaL_error(L, "unix path too long"); unreachable; } *salen = sizeof(struct sockaddr_un); + kprintf("shit %d\n", ((struct sockaddr_in *)ss)->sin_family); return i + 1; } else { - sa->i.sin_family = AF_INET; - sa->i.sin_addr.s_addr = htonl(luaL_optinteger(L, i, 0)); - sa->i.sin_port = htons(luaL_optinteger(L, i + 1, 0)); + ((struct sockaddr_in *)ss)->sin_family = AF_INET; + ((struct sockaddr_in *)ss)->sin_addr.s_addr = + htonl(luaL_optinteger(L, i, 0)); + ((struct sockaddr_in *)ss)->sin_port = htons(luaL_optinteger(L, i + 1, 0)); *salen = sizeof(struct sockaddr_in); + kprintf("wut %d\n", ((struct sockaddr_in *)ss)->sin_family); return i + 2; } } @@ -1236,11 +1233,11 @@ static int LuaUnixSocketpair(lua_State *L) { // └─→ nil, unix.Errno static int LuaUnixBind(lua_State *L) { uint32_t salen; - union SockAddr sa; + struct sockaddr_storage ss; int olderr = errno; - MakeSockaddr(L, 2, &sa, &salen); + MakeSockaddr(L, 2, &ss, &salen); return SysretBool(L, "bind", olderr, - bind(luaL_checkinteger(L, 1), &sa.s, salen)); + bind(luaL_checkinteger(L, 1), &ss, salen)); } // unix.connect(fd:int, ip:uint32, port:uint16) @@ -1249,11 +1246,11 @@ static int LuaUnixBind(lua_State *L) { // └─→ nil, unix.Errno static int LuaUnixConnect(lua_State *L) { uint32_t salen; - union SockAddr sa; + struct sockaddr_storage ss; int olderr = errno; - MakeSockaddr(L, 2, &sa, &salen); + MakeSockaddr(L, 2, &ss, &salen); return SysretBool(L, "connect", olderr, - connect(luaL_checkinteger(L, 1), &sa.s, salen)); + connect(luaL_checkinteger(L, 1), &ss, salen)); } // unix.listen(fd:int[, backlog:int]) @@ -1510,14 +1507,14 @@ static int LuaUnixSendto(lua_State *L) { char *data; size_t size; uint32_t salen; - union SockAddr sa; + struct sockaddr_storage ss; int i, fd, flags, olderr = errno; fd = luaL_checkinteger(L, 1); data = luaL_checklstring(L, 2, &size); - i = MakeSockaddr(L, 3, &sa, &salen); + i = MakeSockaddr(L, 3, &ss, &salen); flags = luaL_optinteger(L, i, 0); return SysretInteger(L, "sendto", olderr, - sendto(fd, data, size, flags, &sa.s, salen)); + sendto(fd, data, size, flags, &ss, salen)); } // unix.shutdown(fd:int, how:int) diff --git a/third_party/third_party.mk b/third_party/third_party.mk index 71579b3ed..b2a00adb6 100644 --- a/third_party/third_party.mk +++ b/third_party/third_party.mk @@ -8,6 +8,7 @@ o/$(MODE)/third_party: \ o/$(MODE)/third_party/chibicc \ o/$(MODE)/third_party/compiler_rt \ o/$(MODE)/third_party/dlmalloc \ + o/$(MODE)/third_party/finger \ o/$(MODE)/third_party/gdtoa \ o/$(MODE)/third_party/getopt \ o/$(MODE)/third_party/libcxx \ diff --git a/tool/net/demo/unix-finger.lua b/tool/net/demo/unix-finger.lua new file mode 100644 index 000000000..4186326bc --- /dev/null +++ b/tool/net/demo/unix-finger.lua @@ -0,0 +1,70 @@ +-- UNIX Finger Example + +local function WriteForm(host, user) + Write([[ + redbean unix finger demo + +

+ + redbean unix finger demo +

+

+ Your redbean is able to function as an finger client. Lua server + pages can use the unix module to implement protocols + that your redbean wasn't originally intended to support. All it + takes is few lines of code! +

+
+ + +
+ + +
+ +
+ ]] % {EscapeHtml(host), EscapeHtml(user)}) +end + +local function main() + if IsPublicIp(GetClientAddr()) then + ServeError(403) + elseif GetMethod() == 'GET' or GetMethod() == 'HEAD' then + WriteForm('graph.no', 'new_york') + elseif GetMethod() == 'POST' then + ip = assert(ResolveIp(GetParam('host'))) + fd = assert(unix.socket()) + assert(unix.connect(fd, ip, 79)) + assert(unix.write(fd, GetParam('user') .. '\r\n')) + response = '' + while true do + data = assert(unix.read(fd)) + if data == '' then + break + end + response = response .. data + end + assert(unix.close(fd)) + WriteForm(GetParam('host'), GetParam('user')) + Write('
\r\n')
+      Write(EscapeHtml(VisualizeControlCodes(response)))
+      Write('
\r\n') + else + ServeError(405) + SetHeader('Allow', 'GET, HEAD, POST') + end +end + +main() diff --git a/tool/net/help.txt b/tool/net/help.txt index c6941cf31..4e36f81f6 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1449,6 +1449,28 @@ FUNCTIONS value will be the `"0b"`-prefixed binary str. The result is currently modulo 2^64. Negative numbers are converted to unsigned. + ResolveIp(hostname:str) + ├─→ ip:uint32 + └─→ nil, error:str + + Gets IP address associated with hostname. + + This function first checks if hostname is already an IP address, in + which case it returns the result of `ParseIp`. Otherwise, it checks + HOSTS.TXT on the local system and returns the first IPv4 address + associated with hostname. If no such entry is found, a DNS lookup is + performed using the system configured (e.g. /etc/resolv.conf) DNS + resolution service. If the service returns multiple IN A records + then only the first one is reutrned. + + The returned address is word-encoded in host endian order. For + example, 1.2.3.4 is encoded as 0x01020304. The `FormatIp` function + may be used to turn this value back into a string. + + If no IP address could be found, then nil is returned alongside a + string of unspecified format describing the error. Calls to this + function may be wrapped in assert() if an exception is desired. + ──────────────────────────────────────────────────────────────────────────────── diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index 00b108609..8b3bff173 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -21,6 +21,7 @@ #include "libc/bits/popcnt.h" #include "libc/calls/calls.h" #include "libc/calls/struct/rusage.h" +#include "libc/dns/dns.h" #include "libc/fmt/itoa.h" #include "libc/fmt/leb128.h" #include "libc/intrin/kprintf.h" @@ -41,7 +42,9 @@ #include "libc/runtime/sysconf.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/rusage.h" +#include "libc/sysv/consts/sock.h" #include "libc/time/time.h" #include "libc/x/x.h" #include "net/http/escape.h" @@ -379,6 +382,27 @@ int LuaSlurp(lua_State *L) { } } +int LuaResolveIp(lua_State *L) { + ssize_t rc; + int64_t ip; + const char *host; + struct addrinfo *ai = NULL; + struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP}; + host = luaL_checkstring(L, 1); + if ((ip = ParseIp(host, -1)) != -1) { + lua_pushinteger(L, ntohl(ai->ai_addr4->sin_addr.s_addr)); + return 1; + } else if ((rc = getaddrinfo(host, "0", &hint, &ai)) == EAI_SUCCESS) { + lua_pushinteger(L, ntohl(ai->ai_addr4->sin_addr.s_addr)); + freeaddrinfo(ai); + return 1; + } else { + lua_pushnil(L); + lua_pushfstring(L, "%s: DNS lookup failed: EAI_%s", host, gai_strerror(rc)); + return 2; + } +} + static int LuaCheckControlFlags(lua_State *L, int idx) { int f = luaL_checkinteger(L, idx); if (f & ~(kControlWs | kControlC0 | kControlC1)) { diff --git a/tool/net/lfuncs.h b/tool/net/lfuncs.h index 5d73b944d..6a8c43fca 100644 --- a/tool/net/lfuncs.h +++ b/tool/net/lfuncs.h @@ -70,6 +70,7 @@ int LuaRand64(lua_State *); int LuaRdrand(lua_State *); int LuaRdseed(lua_State *); int LuaRdtsc(lua_State *); +int LuaResolveIp(lua_State *); int LuaSetLogLevel(lua_State *); int LuaSha1(lua_State *); int LuaSha224(lua_State *); diff --git a/tool/net/net.mk b/tool/net/net.mk index 0c60129ca..fc8f355e5 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -173,6 +173,7 @@ o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \ +o/$(MODE)/tool/net/demo/unix-finger.lua.zip.o \ o/$(MODE)/tool/net/demo/fetch.lua.zip.o \ o/$(MODE)/tool/net/demo/call-lua-module.lua.zip.o \ o/$(MODE)/tool/net/demo/store-asset.lua.zip.o \ @@ -222,6 +223,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \ o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \ + o/$(MODE)/tool/net/demo/unix-finger.lua.zip.o \ o/$(MODE)/tool/net/demo/fetch.lua.zip.o \ o/$(MODE)/tool/net/demo/store-asset.lua.zip.o \ o/$(MODE)/tool/net/demo/call-lua-module.lua.zip.o \ diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 73de05ddb..648acbbdb 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -5131,6 +5131,7 @@ static const luaL_Reg kLuaFuncs[] = { {"Rdrand", LuaRdrand}, // {"Rdseed", LuaRdseed}, // {"Rdtsc", LuaRdtsc}, // + {"ResolveIp", LuaResolveIp}, // {"Route", LuaRoute}, // {"RouteHost", LuaRouteHost}, // {"RoutePath", LuaRoutePath}, //