Compare commits
21 Commits
fbacfecce8
...
87c9e29932
Author | SHA1 | Date | |
---|---|---|---|
87c9e29932 | |||
1037e32e6e | |||
5c70852890 | |||
8ec18ccf75 | |||
3bfdc62035 | |||
7d174c1f7c | |||
3f41110617 | |||
7a69e1d516 | |||
64e943f64a | |||
16dcd4da37 | |||
d892fa1cac | |||
3862a95151 | |||
264ae2e82c | |||
1634761593 | |||
0b40360e7e | |||
590d98d7f7 | |||
07aa9a9abc | |||
fce49bed85 | |||
62b38a6765 | |||
23521bade5 | |||
3b774cab27 |
7
Makefile
7
Makefile
@ -42,7 +42,7 @@ BIN = build/bin
|
|||||||
default: all test
|
default: all test
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true
|
all: dj false fop hru intcmp mm npc peek rpn scrut str strcmp swab true
|
||||||
|
|
||||||
# keep build/include until bindgen(1) has stdin support
|
# keep build/include until bindgen(1) has stdin support
|
||||||
# https://github.com/rust-lang/rust-bindgen/issues/2703
|
# https://github.com/rust-lang/rust-bindgen/issues/2703
|
||||||
@ -137,6 +137,11 @@ npc: build/bin/npc
|
|||||||
build/bin/npc: src/npc.c build
|
build/bin/npc: src/npc.c build
|
||||||
$(CC) $(CFLAGS) -o $@ src/npc.c
|
$(CC) $(CFLAGS) -o $@ src/npc.c
|
||||||
|
|
||||||
|
.PHONY: peek
|
||||||
|
peek: build/bin/peek
|
||||||
|
build/bin/peek: src/peek.c build
|
||||||
|
$(CC) $(CFLAGS) -o $@ src/peek.c
|
||||||
|
|
||||||
.PHONY: rpn
|
.PHONY: rpn
|
||||||
rpn: build/bin/rpn
|
rpn: build/bin/rpn
|
||||||
build/bin/rpn: src/rpn.rs build rustlibs
|
build/bin/rpn: src/rpn.rs build rustlibs
|
||||||
|
111
docs/peek.1
Normal file
111
docs/peek.1
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
.\" Copyright (c) 2023-2024 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
|
||||||
|
.\"
|
||||||
|
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
|
||||||
|
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
|
||||||
|
.\"
|
||||||
|
.TH PEEK 1 2024-08-14 "Harakit X.X.X"
|
||||||
|
.SH NAME
|
||||||
|
peek \(en read from the standard input, furtively
|
||||||
|
.\"
|
||||||
|
.SH SYNOPSIS
|
||||||
|
|
||||||
|
peek
|
||||||
|
.RB [ -i ]
|
||||||
|
.\"
|
||||||
|
.SH DESCRIPTION
|
||||||
|
|
||||||
|
Read input from the standard input with terminal echo disabled.
|
||||||
|
.\"
|
||||||
|
.SH OPTIONS
|
||||||
|
|
||||||
|
.IP \fB-i\fP
|
||||||
|
Allows input to come from sources other than terminals (pipes).
|
||||||
|
.\"
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
|
||||||
|
In the event of an error, a debug message will be printed and the program will
|
||||||
|
exit with the appropriate
|
||||||
|
.BR sysexits.h (3)
|
||||||
|
error code.
|
||||||
|
|
||||||
|
In order to ensure the user\(cqs terminal is still usable after premature
|
||||||
|
termination, the program attempts to handle the SIGINT signal; if it cannot,
|
||||||
|
an error message is printed and execution continues. If the program is
|
||||||
|
interrupted, it exits unsuccessfully without an error message.
|
||||||
|
.\"
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
This tool was originally written to accept passwords in shell scripts as an
|
||||||
|
extremely simple alternative to the GNU Privacy Guard project\(cqs
|
||||||
|
.BR pinentry (1)
|
||||||
|
utility.
|
||||||
|
|
||||||
|
Accepting input without showing what is being typed is useful when keying in
|
||||||
|
secrets in public settings or in places where surveillance cameras are
|
||||||
|
installed.
|
||||||
|
.\"
|
||||||
|
.SH CAVEATS
|
||||||
|
|
||||||
|
This program does nothing to prevent others from seeing the key presses input to
|
||||||
|
a keyboard. It also does not protect against the sound of typing being analyzed
|
||||||
|
to determine what was input without needing to see screen or keyboard.
|
||||||
|
|
||||||
|
Accepting secrets in shell scripts is probably not advisable.
|
||||||
|
|
||||||
|
On systems that support it, the
|
||||||
|
.BR ioctl (2)
|
||||||
|
command TIOCSTI can be used to insert characters into the standard input. This
|
||||||
|
doesn't allow snooping but can be used for general mischief.
|
||||||
|
.\"
|
||||||
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
This is an
|
||||||
|
.BR sh (1p)
|
||||||
|
command line that hashes a given password. It uses
|
||||||
|
.BR head (1p)
|
||||||
|
to only accept one line of input,
|
||||||
|
.BR xargs (1p)
|
||||||
|
and
|
||||||
|
.BR printf (1p)
|
||||||
|
to strip the trailing newline,
|
||||||
|
.BR htpasswd (1)
|
||||||
|
from Apache\(cqs utilities to hash the input with the bcrypt algorithm, and
|
||||||
|
.BR cut (1p)
|
||||||
|
to print only the resulting hash:
|
||||||
|
|
||||||
|
.RS
|
||||||
|
$ peek | head -n 1 | xargs printf '%s' | htpasswd -nBi _ | cut -d : -f 2
|
||||||
|
.RE
|
||||||
|
|
||||||
|
This is an
|
||||||
|
.BR sh (1p)
|
||||||
|
command line that allows a user to write blindly into a text file but displaying
|
||||||
|
only written lines. Some writers have the habit of prematurely revising their
|
||||||
|
work and use tools with functionality similar to this to prevent it.
|
||||||
|
It uses
|
||||||
|
.BR mm (1)
|
||||||
|
to pipe the output of the program to both the standard error and the regular
|
||||||
|
file writing.txt:
|
||||||
|
|
||||||
|
.RS
|
||||||
|
$ echo Input ^D to quit. && peek | mm -eo - >writing.txt
|
||||||
|
.RE
|
||||||
|
.\"
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by DTB
|
||||||
|
.MT trinity@trinity.moe
|
||||||
|
.ME .
|
||||||
|
.\"
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
Copyright \(co 2023-2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||||
|
<https://gnu.org/licenses/gpl.html>.
|
||||||
|
.\"
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR ioctl (2),
|
||||||
|
.BR ioctl_tty (2),
|
||||||
|
.BR read (1p),
|
||||||
|
.BR sh (1p),
|
||||||
|
.BR stty (1p)
|
147
src/peek.c
Normal file
147
src/peek.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023–2024 DTB <trinity@trinity.moe>
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||||
|
* later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h> /* sigaction(2), signal(2), struct sigaction, SIGINT */
|
||||||
|
#include <stdbool.h> /* bool */
|
||||||
|
#include <stdio.h> /* fprintf(3), fgetc(3), perror(3), fputc(3), stderr, stdin,
|
||||||
|
* stdout, EOF, NULL */
|
||||||
|
#include <stdlib.h> /* exit(3), EXIT_FAILURE */
|
||||||
|
#include <sysexits.h> /* EX_IOERR, EX_OK, EX_USAGE */
|
||||||
|
#include <termios.h> /* tcgetattr(3), tcsetattr(3), struct termios, ECHO */
|
||||||
|
#include <unistd.h> /* getopt(3), isatty(3), pledge(2), unveil(2),
|
||||||
|
* STDIN_FILENO */
|
||||||
|
|
||||||
|
char *program_name = "peek";
|
||||||
|
|
||||||
|
/* Restores terminal echo; otherwise when a user ^Cs the terminal would
|
||||||
|
* continue to not display typed text. If sig isn't zero, this will terminate
|
||||||
|
* the program. */
|
||||||
|
static void
|
||||||
|
restore_echo(int sig) {
|
||||||
|
static struct termios t;
|
||||||
|
|
||||||
|
/* Failure isn't reported because this is the termination routine anyway;
|
||||||
|
* errors will be obvious. */
|
||||||
|
if (tcgetattr(STDIN_FILENO, &t) == 0) {
|
||||||
|
t.c_lflag |= ECHO;
|
||||||
|
(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sig != 0) { exit(EXIT_FAILURE); } /* Terminated by signal. */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ioerr(char *argv0) {
|
||||||
|
perror(argv0);
|
||||||
|
restore_echo(0);
|
||||||
|
return EX_IOERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
usage(char *argv0) {
|
||||||
|
(void)fprintf(stderr, "Usage: %s [-i]\n", argv0);
|
||||||
|
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
bool is_term; /* Is stdin a terminal? */
|
||||||
|
bool must_be_term = 1; /* Must it be? */
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
if (pledge("stdio tty unveil", "") != 0 || unveil(NULL, NULL) != 0) {
|
||||||
|
/* This isn't fatal; these return values could be cast to void just as
|
||||||
|
* easily. */
|
||||||
|
(void)perror(argv[0] == NULL ? argv[0] : program_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
is_term = isatty(STDIN_FILENO);
|
||||||
|
|
||||||
|
if (argc > 0) { /* option parsing */
|
||||||
|
int c;
|
||||||
|
|
||||||
|
program_name = argv[0];
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "i")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'i': must_be_term = 0; break;
|
||||||
|
default: return usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > optind) { return usage(argv[0]); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_term && must_be_term) {
|
||||||
|
(void)fprintf(
|
||||||
|
stderr,
|
||||||
|
"%s: Must be run in a terminal (specify -i to skip this check)\n",
|
||||||
|
argv[0]
|
||||||
|
);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_term) {
|
||||||
|
{ /* Install signal handler */
|
||||||
|
/* There isn't a difference in functionality between the signal(2)
|
||||||
|
* and sigaction(2) methods. sigaction(2) is vastly preferred for
|
||||||
|
* portability but some older systems only have signal(2). */
|
||||||
|
/* Errors aren't terminating because the worst that happens is some
|
||||||
|
* terminal phooeyness if things go awry. */
|
||||||
|
#if defined _POSIX_C_SOURCE
|
||||||
|
struct sigaction act = { 0 };
|
||||||
|
|
||||||
|
act.sa_handler = restore_echo;
|
||||||
|
if (sigaction(SIGINT, &act, NULL) != 0) { perror(program_name); }
|
||||||
|
#else
|
||||||
|
if (signal(SIGINT, restore_echo) == SIG_ERR) {
|
||||||
|
perror(program_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* Banish terminal echo */
|
||||||
|
/* This terminates when it fails because it's the whole point of
|
||||||
|
* the program. */
|
||||||
|
struct termios t;
|
||||||
|
|
||||||
|
if (tcgetattr(STDIN_FILENO, &t) != 0) {
|
||||||
|
return ioerr(program_name);
|
||||||
|
}
|
||||||
|
t.c_lflag ^= ECHO;
|
||||||
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) != 0) {
|
||||||
|
return ioerr(program_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* Input loop */
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = fgetc(stdin)) != EOF) {
|
||||||
|
if (fputc(c, stdout) == EOF) { return ioerr(program_name); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_term) { restore_echo(0); }
|
||||||
|
|
||||||
|
return EX_OK;
|
||||||
|
}
|
24
tests/bonsai/peek.mk
Executable file
24
tests/bonsai/peek.mk
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2024 DTB <trinity@trinity.moe>
|
||||||
|
# SPDX-License-Identifier: FSFAP
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice and this
|
||||||
|
# notice are preserved. This file is offered as-is, without any warranty.
|
||||||
|
|
||||||
|
# Testing peek is hard as it requires visual confirmation that text isn't being
|
||||||
|
# echoed. These tests don't go that far but are a start, and have already
|
||||||
|
# caught a bug in -i behavior.
|
||||||
|
|
||||||
|
.PHONY: peek_tests
|
||||||
|
peek_tests: peek_help peek_stdio
|
||||||
|
|
||||||
|
.PHONY: peek_help
|
||||||
|
peek_help: $(BIN)/peek
|
||||||
|
! $(BIN)/peek -h
|
||||||
|
|
||||||
|
.PHONY: peek_stdio
|
||||||
|
# Test peek -i
|
||||||
|
peek_stdio: $(BIN)/peek
|
||||||
|
printf 'Test.\n' \
|
||||||
|
| $(BIN)/peek -i \
|
||||||
|
| xargs test 'Test.' =
|
Loading…
Reference in New Issue
Block a user