peek(1): fix erroring on stdin/stdout redirection

This commit is contained in:
dtb 2024-08-31 22:19:13 -06:00
parent 5c70852890
commit 1037e32e6e
Signed by: trinity
GPG Key ID: 34C0543BBB6AF81B

View File

@ -62,6 +62,9 @@ usage(char *argv0) {
} }
int main(int argc, char *argv[]){ int main(int argc, char *argv[]){
bool is_term; /* Is stdin a terminal? */
bool must_be_term = 1; /* Must it be? */
#ifdef __OpenBSD__ #ifdef __OpenBSD__
if (pledge("stdio tty unveil", "") != 0 || unveil(NULL, NULL) != 0) { if (pledge("stdio tty unveil", "") != 0 || unveil(NULL, NULL) != 0) {
/* This isn't fatal; these return values could be cast to void just as /* This isn't fatal; these return values could be cast to void just as
@ -70,58 +73,63 @@ int main(int argc, char *argv[]){
} }
#endif #endif
is_term = isatty(STDIN_FILENO);
if (argc > 0) { /* option parsing */ if (argc > 0) { /* option parsing */
bool allow_nonterminals;
int c; int c;
program_name = argv[0]; program_name = argv[0];
allow_nonterminals = 0;
while ((c = getopt(argc, argv, "i")) != -1) { while ((c = getopt(argc, argv, "i")) != -1) {
switch (c) { switch (c) {
case 'i': allow_nonterminals = 1; break; case 'i': must_be_term = 0; break;
default: return usage(argv[0]); default: return usage(argv[0]);
} }
} }
if (argc > optind) { 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 (specify -i to skip this"
" check)\n",
argv[0]
);
return EX_USAGE;
}
} }
{ /* Install signal handler */ if (!is_term && must_be_term) {
/* There isn't a difference in functionality between the signal(2) and (void)fprintf(
* sigaction(2) methods. sigaction(2) is vastly preferred for stderr,
* portability but some configurations can only use signal(2). */ "%s: Must be run in a terminal (specify -i to skip this check)\n",
/* Errors aren't terminating because the worst that happens is some argv[0]
* terminal phooeyness if things go awry. */ );
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 #if defined _POSIX_C_SOURCE
struct sigaction act = { 0 }; struct sigaction act = { 0 };
act.sa_handler = restore_echo; act.sa_handler = restore_echo;
if (sigaction(SIGINT, &act, NULL) != 0) { perror(program_name); } if (sigaction(SIGINT, &act, NULL) != 0) { perror(program_name); }
#else #else
if (signal(SIGINT, restore_echo) == SIG_ERR) { perror(program_name); } if (signal(SIGINT, restore_echo) == SIG_ERR) {
perror(program_name);
}
#endif #endif
} }
/* Banish terminal echo; this terminates when it fails, because it's the { /* Banish terminal echo */
* whole point of the program. */ /* This terminates when it fails because it's the whole point of
{ * the program. */
struct termios t; struct termios t;
if (tcgetattr(STDIN_FILENO, &t) != 0) { return ioerr(program_name); } if (tcgetattr(STDIN_FILENO, &t) != 0) {
t.c_lflag ^= ECHO; return ioerr(program_name);
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) != 0) { }
return ioerr(program_name); t.c_lflag ^= ECHO;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) != 0) {
return ioerr(program_name);
}
} }
} }
@ -133,7 +141,7 @@ int main(int argc, char *argv[]){
} }
} }
restore_echo(0); if (is_term) { restore_echo(0); }
return EX_OK; return EX_OK;
} }