30 Commits

Author SHA1 Message Date
DTB
21ee79a929 peek(1): warn on pledge(2) or unveil(2) errors 2024-08-28 18:17:58 -06:00
DTB
4dc1900339 peek(1): pledge(2) and unveil(2) on OpenBSD 2024-08-27 21:16:12 -06:00
DTB
15c4f0cb8a peek.1: correct references to use the 1p section, add reference to stty(1p) 2024-08-14 11:06:31 -06:00
DTB
b68be7ff62 peek(1): fix ioerr typos 2024-07-27 18:51:09 -06:00
DTB
a217c4f631 Merge branch 'main' into peek 2024-07-27 18:46:48 -06:00
DTB
3f23e437e8 peek(1): more style fixes 2024-07-26 07:58:34 -06:00
DTB
a927c39c06 peek(1): update style 2024-07-26 07:42:05 -06:00
DTB
e90d25e30f Merge branch 'strcmp' 2024-07-15 19:52:26 -06:00
DTB
71f372d2c2 Merge branch 'intcmp' 2024-07-15 15:21:31 -06:00
DTB
27ff64dffa intcmp(1): add comments 2024-07-15 14:51:54 -06:00
DTB
becb3bac4e strcmp(1): code clarification 2024-07-15 14:40:26 -06:00
DTB
efb3ce626d strcmp(1): fix program_name type 2024-07-15 04:29:43 -06:00
DTB
16f23e11c0 strcmp.1: update docs to match utility 2024-07-15 04:26:57 -06:00
DTB
d87c278be5 strcmp(1): re-style, tweak exits 2024-07-15 04:21:50 -06:00
DTB
5caefbb465 strcmp(1): note used sysexit 2024-07-15 03:45:36 -06:00
DTB
8d743dab7a strcmp(1): add copyright header
I could trace strcmp(1) as far back as
<293436c5ad/src/streq.c>
in my repo.
2024-07-15 03:43:25 -06:00
DTB
2f2270322a intcmp(1): rewrite in rust 2024-07-15 03:14:57 -06:00
DTB
699893af89 intcmp(1): initial rust impl 2024-07-15 03:09:00 -06:00
DTB
26558d6ffe Merge branch 'main' into peek 2024-06-28 08:40:17 -06:00
DTB
c7a4cd1d19 peek.1: s/inputted/input/ 2024-06-28 08:37:49 -06:00
DTB
e807a49612 peek.1: fix version string 2024-06-28 08:36:47 -06:00
DTB
70ee886b83 peek.1: fix wording on -i 2024-06-26 09:55:32 -06:00
DTB
ff993eebdc Makefile: all: add peek 2024-06-26 09:46:32 -06:00
DTB
262b3c18fb Merge branch 'main' into peek 2024-06-26 09:40:59 -06:00
3db83fd79c peek.1: updates to be more consistent with current documentation 2024-06-17 22:28:41 -06:00
DTB
6d3f084d9c peek(1): remove unused variables, clean up some typos 2024-04-18 10:14:52 -06:00
DTB
c295f531cb peek(1): correct grammar 2024-04-18 10:04:26 -06:00
DTB
c7739612a7 peek(1): strip down to bare essentials, rewrite man page to match 2024-04-18 10:03:02 -06:00
DTB
46b607384a peek(1): remove -p 2024-04-18 09:08:08 -06:00
DTB
4e5fc680e9 Import peek(1) from trinity/src 2024-04-17 16:37:54 -06:00
7 changed files with 374 additions and 105 deletions

View File

@@ -32,7 +32,7 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
CFLAGS += -I$(SYSEXITS)
.PHONY: all
all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true
all: docs dj false fop hru intcmp mm npc peek rpn scrut str strcmp swab true
# keep build/include until bindgen(1) has stdin support
# https://github.com/rust-lang/rust-bindgen/issues/2703
@@ -109,8 +109,8 @@ build/bin/hru: src/hru.rs build rustlibs
.PHONY: intcmp
intcmp: build/bin/intcmp
build/bin/intcmp: src/intcmp.c build
$(CC) $(CFLAGS) -o $@ src/intcmp.c
build/bin/intcmp: src/intcmp.rs build rustlibs
$(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/intcmp.rs
.PHONY: mm
mm: build/bin/mm
@@ -120,7 +120,12 @@ build/bin/mm: src/mm.rs build rustlibs
.PHONY: npc
npc: build/bin/npc
build/bin/npc: src/npc.c build
$(CC) $(CFLAGAS) -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
rpn: build/bin/rpn

111
docs/peek.1 Normal file
View 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)

View File

@@ -4,7 +4,7 @@
.\" 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 STRCMP 1 2024-06-17 "Harakit X.X.X"
.TH STRCMP 1 2024-07-15 "Harakit X.X.X"
.SH NAME
strcmp \(en compare strings
.\"
@@ -20,15 +20,15 @@ Check whether string arguments are the same.
.SH DIAGNOSTICS
The program will exit successfully if the strings are identical. Otherwise, it
will exit with an error code of 1 if a string passed has a lesser byte value
than one of the prior strings:
will exit with an error code less than 128 if a string passed has a lesser byte
value than one of the prior strings:
.RS
strcmp b a
.RE
or with an error code of 255 if it has a greater byte value than one of the
prior strings:
or with an error code greater than 128 if it has a greater byte value than one
of the prior strings:
.RS
strcmp a b

View File

@@ -1,82 +0,0 @@
/*
* Copyright (c) 2023 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 <errno.h> /* errno */
#include <stdio.h> /* fprintf(3), stderr */
#include <stdlib.h> /* strtol(3), size_t, EXIT_FAILURE */
#include <unistd.h> /* getopt(3), optind */
#include <sysexits.h>
/* 0b00? */ /* Equal | -e | 0b001 | 1 */
#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */
/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */
#define GREATER 0x02 /* Less | -l | 0b100 | 4 */
/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */
#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */
static char *program_name = "intcmp";
int main(int argc, char *argv[]){
int c;
size_t i;
unsigned char mode;
int r; /* reference integer */
mode = 0;
if(argc < 3)
goto usage;
while((c = getopt(argc, argv, "egl")) != -1)
switch(c){
case 'e': mode |= EQUAL; break;
case 'g': mode |= GREATER; break;
case 'l': mode |= LESS; break;
default: goto usage;
}
if(optind + 2 /* ref cmp */ > argc){
usage: fprintf(stderr,
"Usage: %s [-egl] integer integer...\n",
argv[0] == NULL ? program_name : argv[0]);
return EX_USAGE;
}
i = optind;
do{ r = c;
c = strtol(argv[i], &argv[i], 10);
if(*argv[i] != '\0' || errno != 0){
fprintf(stderr, "%s: argument #%d: Invalid integer\n",
argv[0], (int)i);
return EX_USAGE;
}
if(i == optind)
continue;
/* rule enforcement; if a mode isn't permitted and the numbers
* correspond to it, return 1 */
if( (!(mode & EQUAL) && r == c)
|| (!(mode & GREATER) && r > c)
|| (!(mode & LESS) && r < c))
return 1;
}while(++i < argc);
return 0;
}

79
src/intcmp.rs Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 20232024 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/.
*/
use std::{
env::args,
process::ExitCode
};
extern crate getopt;
use getopt::GetOpt;
extern crate sysexits;
use sysexits::EX_USAGE;
fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} [-egl] integer integer...", s);
ExitCode::from(EX_USAGE as u8)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
let mut e = false; /* args can be == */
let mut g = false; /* args can be > */
let mut l = false; /* args can be < */
let mut optind = 0;
if argv.len() < 3 { return usage(&argv[0]); }
while let Some(opt) = argv.getopt("egl") {
match opt.opt() {
Ok("e") => e = true,
Ok("g") => g = true,
Ok("l") => l = true,
_ => { return usage(&argv[0]); },
}
optind = opt.ind();
}
if argv.len() - optind < 2 /* see usage */ { return usage(&argv[0]); }
let mut prev: Option<usize> = None; /* no previous operand */
let mut currn: usize;
for arg in argv.iter().skip(optind) { /* iterate operands */
match arg.parse::<usize>() { /* parse current operand */
Ok(n) => currn = n,
_ => {
eprintln!("{}: {}: Invalid integer", &argv[0], arg);
return ExitCode::from(EX_USAGE as u8);
}
}
if let Some(prevn) = prev { /* if there was a previous opr., test */
if (!e && prevn == currn)
|| (!g && prevn > currn)
|| (!l && prevn < currn)
{ return ExitCode::FAILURE; }
}
prev = Some(currn); /* there is a previous operand */
}
ExitCode::SUCCESS
}

137
src/peek.c Normal file
View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 20232024 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 <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[]){
#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
if (argc > 0) { /* option parsing */
char allow_nonterminals;
int c;
program_name = argv[0];
allow_nonterminals = 0;
while ((c = getopt(argc, argv, "i")) != -1) {
switch (c) {
case 'i': allow_nonterminals = 1; break;
default: return usage(argv[0]);
}
}
if (argc > optind) { return usage(argv[0]); }
if (!allow_nonterminals && isatty(STDIN_FILENO) != 1) {
(void)fprintf(
stderr,
"%s: Must be run in a terminal (option -i skips this check)\n",
argv[0]
);
return EX_USAGE;
}
}
{ /* 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 configurations can only use 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); }
}
}
restore_echo(0);
return EX_OK;
}

View File

@@ -1,24 +1,43 @@
#include <stdio.h> /* fprintf(3), stderr */
#include <stdlib.h> /* EXIT_FAILURE */
#include <sysexits.h>
/*
* Copyright (c) 20222024 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/.
*/
static char *program_name = "strcmp";
#include <stdio.h> /* fprintf(3), stderr */
#include <stdlib.h> /* size_t */
#include <sysexits.h> /* EX_USAGE */
char *program_name = "strcmp";
int main(int argc, char *argv[]){
int i;
if(argc < 3){
if (argc < 3) {
fprintf(stderr, "Usage: %s string string...\n",
argv[0] == NULL ? program_name : argv[0]);
argv[0] == NULL ? program_name : argv[0]
);
return EX_USAGE;
}
for(; *argv[1] != '\0'; ++argv[1])
for(i = 2; i < argc; ++i)
if(*argv[i-1] > *argv[i])
return 1;
else if(*argv[i-1] < *argv[i]++)
return -1; /* actually 255 */
/* This compares the Nth character of arg[2] onward with argv[1]'s Nth
* character, rather than comparing each arg with argv[1] sequentially. */
for (; *argv[1] != '\0'; ++argv[1]) { /* iterate chars in argv[1] */
for (size_t i = 2; i < argc; ++argv[i], ++i) { /* iterate &argv[2] */
/* this never overruns because of nul termination */
if (*argv[i-1] != *argv[i]) { return *argv[i-1] - *argv[i]; }
}
}
return 0;
}