|
Home > Archive > Unix Programming > August 2007 > How to temporarily disable the keyboard
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
How to temporarily disable the keyboard
|
|
| Army1987 2007-08-21, 7:22 am |
| I have a program reading many, many data from /dev/random.
I have included something like this to ask the user for more
entropy:
fputs("Please move around the mouse and/or type randomly", stderr);
res = fread(randfp, pool, sizeof *pool); /* randfp is /dev/random */
fputs("\r \r", stderr);
so that if the read blocks due to there not being enough entropy
in the pool, the user knows what to do. (I want the data to be as
random as possible, so I'd prefer not to use /dev/urandom.)
Is there a way to temporarily stop the keyboard input from going
to stdin and from being echoed, while still augmenting
/dev/random's entropy pool?
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Ivan Gotovchits 2007-08-21, 7:22 am |
| Army1987 wrote:
> I have a program reading many, many data from /dev/random.
> I have included something like this to ask the user for more
> entropy:
>
> fputs("Please move around the mouse and/or type randomly", stderr);
> res = fread(randfp, pool, sizeof *pool); /* randfp is /dev/random */
> fputs("\r \r", stderr);
>
> so that if the read blocks due to there not being enough entropy
> in the pool, the user knows what to do. (I want the data to be as
> random as possible, so I'd prefer not to use /dev/urandom.)
> Is there a way to temporarily stop the keyboard input from going
> to stdin and from being echoed, while still augmenting
> /dev/random's entropy pool?
>
I'am not sure, that I correctly understand what you whant, but I thing that
`select()' can help or you.
Or you can make two threads - one will read entropy from /dev/random, and
other will read it from the user.
| |
| Army1987 2007-08-21, 7:22 am |
| On Tue, 21 Aug 2007 11:45:11 +0200, Army1987 wrote:
> res = fread(randfp, pool, sizeof *pool); /* randfp is /dev/random */
Should be fread(pool, sizeof *pool, 1, randfp) of course...
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-21, 7:22 am |
| On Tue, 21 Aug 2007 14:45:44 +0400, Ivan Gotovchits wrote:
> Army1987 wrote:
>
> I'am not sure, that I correctly understand what you whant, but I thing that
> `select()' can help or you.
No, I was thinking about something like:
fputs("Please move around the mouse and/or type randomly", stderr);
block_keyboard();
res = fread(pool, sizeof *pool, 1, randfp);
fputs("\r \r", stderr);
unblock_keyboard();
where after block_keyboard(), what the user types doesn't go to
stdin, and isn't echoed to the screen.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Ivan Gotovchits 2007-08-21, 7:22 am |
| Army1987 wrote:
> On Tue, 21 Aug 2007 14:45:44 +0400, Ivan Gotovchits wrote:
>
> No, I was thinking about something like:
>
> fputs("Please move around the mouse and/or type randomly", stderr);
> block_keyboard();
> res = fread(pool, sizeof *pool, 1, randfp);
> fputs("\r \r", stderr);
> unblock_keyboard();
> where after block_keyboard(), what the user types doesn't go to
> stdin, and isn't echoed to the screen.
The idea is:
block_keyboard()
{
int nd;
nd = fopen("/dev/null", O_RDWR);
dup2(nd, STDIN_FILENO);
}
unblock_keyboard()
{
int nd;
nd = open("/dev/console", O_RDONLY);
dup2(nd, STDIN_FILENO);
}
may be some errors, not tested myself ))
| |
| Ivan Gotovchits 2007-08-21, 7:22 am |
| Ivan Gotovchits wrote:
<snip>
> The idea is:
>
> block_keyboard()
> {
> int nd;
> nd = fopen("/dev/null", O_RDWR);
> dup2(nd, STDIN_FILENO);
> }
>
> unblock_keyboard()
> {
> int nd;
> nd = open("/dev/console", O_RDONLY);
> dup2(nd, STDIN_FILENO);
>
> }
>
> may be some errors, not tested myself ))
not `fopen' but `open', ofcourse ))
| |
| David Schwartz 2007-08-21, 7:22 am |
| On Aug 21, 4:09 am, Army1987 <army1...@NOSPAM.it> wrote:
> On Tue, 21 Aug 2007 14:45:44 +0400, Ivan Gotovchits wrote:
>
>
>
>
>
> No, I was thinking about something like:
>
> fputs("Please move around the mouse and/or type randomly", stderr);
> block_keyboard();
> res = fread(pool, sizeof *pool, 1, randfp);
> fputs("\r \r", stderr);
> unblock_keyboard();
> where after block_keyboard(), what the user types doesn't go to
> stdin, and isn't echoed to the screen.
How do you know the user is anywhere near the keyboard? And what does
that have to do with "stdin" which is per process and may or may not
be the system keyboard?
By "keyboard" do you mean literally the system keyboard? Or do you
mean whatever terminal the user of your program happens to be at? Why
can't you just claim stdin/stdout the same way every other program
does?
DS
| |
| Army1987 2007-08-21, 1:21 pm |
| On Tue, 21 Aug 2007 04:35:13 -0700, David Schwartz wrote:
> On Aug 21, 4:09 am, Army1987 <army1...@NOSPAM.it> wrote:
>
> How do you know the user is anywhere near the keyboard? And what does
> that have to do with "stdin" which is per process and may or may not
> be the system keyboard?
>
> By "keyboard" do you mean literally the system keyboard? Or do you
> mean whatever terminal the user of your program happens to be at? Why
> can't you just claim stdin/stdout the same way every other program
> does?
I'll try to be clearer:
I mean, if I am running a program and the input isn't redirected,
whenever I hit a key it is echoed to the terminal emulator or
console, and also, as soon as I hit Enter all the characters I
type become available for reading with getchar().
I am trying to temporarily disable this: that is, between
block_keyboard() and unblock_keyboard() the characters typed won't
show on the screen, and (if the input of the program isn't
redirected) don't go to stdin, that is, a sequence of getchar()
calls, after the last character typed before block_keyboard()
should read the first character typed after unblock_keyboard().
Anyway, the OS must continue to see the keyboard, so that I can
still send signals to that program via Ctrl-C etc., I can still
use the keyboard in other programs, etc.
IOW, between block_keyboard() and unblock_keyboard() the program
should behave as if the user weren't typing anything, but all the
other processes should behave normally.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-21, 1:21 pm |
| On Tue, 21 Aug 2007 15:17:19 +0400, Ivan Gotovchits wrote:
> Ivan Gotovchits wrote:
>
> <snip>
> not `fopen' but `open', ofcourse ))
It doesn't work. It doesn't disable echoing, it hides *all* of the
characters to the program, and after it exits the shell tries to
interpret them as commands:
army1987@army1987-laptop:~$ cat keyblock.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
void block_keyboard(void)
{
int nd;
nd = open("/dev/null", O_RDWR);
dup2(nd, STDIN_FILENO);
}
void unblock_keyboard(void)
{
int nd;
nd = open("/dev/console", O_RDONLY);
dup2(nd, STDIN_FILENO);
}
int main(void)
{
int ch;
sleep(5);
fputs("keyboard blocked NOW! ", stderr);
block_keyboard();
sleep(5);
fputs("keyboard unblocked NOW! ", stderr);
unblock_keyboard();
sleep(5);
puts("You typed:");
while ((ch = getchar()) != EOF) {
putchar(ch);
}
}
army1987@army1987-laptop:~$ cc keyblock.c -o keyblock
army1987@army1987-laptop:~$ ./keyblock
123456
5678keyboard blocked NOW! 9056789043keyboard unblocked NOW! 5fyjuikgh
You typed:
army1987@army1987-laptop:~$ 123456
bash: 123456: command not found
army1987@army1987-laptop:~$ 567890567890435fyjuikgh
bash: 567890567890435fyjuikgh: command not found
army1987@army1987-laptop:~$
What I am trying to do is that, between block_keyboard() and
unblock_keyboard() the program should behave as if I weren't
typing anything (except for signals sent via Ctrl-C etc.), but the
OS and all other processes should continue to work normally.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
|
| On Aug 21, 4:43 pm, Army1987 <army1...@NOSPAM.it> wrote:
> On Tue, 21 Aug 2007 15:17:19 +0400, Ivan Gotovchits wrote:
>
>
>
>
>
>
> It doesn't work. It doesn't disable echoing, it hides *all* of the
> characters to the program, and after it exits the shell tries to
> interpret them as commands:
>
> army1987@army1987-laptop:~$ cat keyblock.c
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <stdio.h>
>
> void block_keyboard(void)
> {
> int nd;
> nd = open("/dev/null", O_RDWR);
> dup2(nd, STDIN_FILENO);
>
> }
>
> void unblock_keyboard(void)
> {
> int nd;
> nd = open("/dev/console", O_RDONLY);
> dup2(nd, STDIN_FILENO);
>
> }
>
> int main(void)
> {
> int ch;
> sleep(5);
> fputs("keyboard blocked NOW! ", stderr);
> block_keyboard();
> sleep(5);
> fputs("keyboard unblocked NOW! ", stderr);
> unblock_keyboard();
> sleep(5);
> puts("You typed:");
> while ((ch = getchar()) != EOF) {
> putchar(ch);
> }}
>
> army1987@army1987-laptop:~$ cc keyblock.c -o keyblock
> army1987@army1987-laptop:~$ ./keyblock
> 123456
> 5678keyboard blocked NOW! 9056789043keyboard unblocked NOW! 5fyjuikgh
> You typed:
> army1987@army1987-laptop:~$ 123456
> bash: 123456: command not found
> army1987@army1987-laptop:~$ 567890567890435fyjuikgh
> bash: 567890567890435fyjuikgh: command not found
> army1987@army1987-laptop:~$
>
> What I am trying to do is that, between block_keyboard() and
> unblock_keyboard() the program should behave as if I weren't
> typing anything (except for signals sent via Ctrl-C etc.), but the
> OS and all other processes should continue to work normally.
> --
> Army1987 (Replace "NOSPAM" with "email")
> No-one ever won a game by resigning. -- S. Tartakower
to disable echo output use `tcsetattr', see man, for more ))
and add
fsync(STDIN_FILENO); - after block and unblock functions
and
close(nd); - into the end ot this functions.
May be it can help ))
| |
| Army1987 2007-08-21, 1:21 pm |
| On Tue, 21 Aug 2007 13:21:07 +0000, crox wrote:
> On Aug 21, 4:43 pm, Army1987 <army1...@NOSPAM.it> wrote:
[snip]
[signature snipped][vbcol=seagreen]
> to disable echo output use `tcsetattr', see man, for more ))
> and add
> fsync(STDIN_FILENO); - after block and unblock functions
> and
> close(nd); - into the end ot this functions.
> May be it can help ))
It does disable echo, but it doesn't even re-enable the keyboard.
In the example below, I typed "1234567890" before the first fputs
to stderr, "abcdefghijk" between the two, and "opqrstuv" after the
second one. The program did not even see the digits, and after it
exited, not even the shell interpreted the keyboard. The only key
which was working was Enter, which attempted to interpret all the
former input as a command. Not even the newline before the prompt
worked anymore.
army1987@army1987-laptop:~$ cat keyblock.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
void block_keyboard(void)
{
int nd;
struct termios attr;
tcgetattr(STDIN_FILENO, &attr);
attr.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
nd = open("/dev/null", O_RDWR);
dup2(nd, STDIN_FILENO);
close(nd);
fsync(STDIN_FILENO);
}
void unblock_keyboard(void)
{
int nd;
struct termios attr;
tcgetattr(STDIN_FILENO, &attr);
attr.c_lflag |= ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
nd = open("/dev/console", O_RDONLY);
dup2(nd, STDIN_FILENO);
close(nd);
fsync(STDIN_FILENO);
}
int main(void)
{
int ch;
sleep(5);
fputs("keyboard blocked NOW! ", stderr);
block_keyboard();
sleep(5);
fputs("keyboard unblocked NOW! ", stderr);
unblock_keyboard();
sleep(5);
puts("You typed:");
while ((ch = getchar()) != EOF) {
putchar(ch);
}
}
army1987@army1987-laptop:~$ cc keyblock.c -o keyblock
army1987@army1987-laptop:~$ ./keyblock
1234567890keyboard blocked NOW! keyboard unblocked NOW! You typed:
army1987@army1987-laptop:~$ bash: 1234567890abcdefghijkopqrstuv: command not found
army1987@army1987-laptop:~$ bash: 1234567890abcdefghijkopqrstuv: command not found
army1987@army1987-laptop:~$ army1987@army1987-laptop:~$ army1987@army1987-laptop:~$ army1987@army1987-laptop:~$
What I would expect is:
army1987@army1987-laptop:~$ ./keyblock
1234567890keyboard blocked NOW! keyboard unblocked NOW! opqrstuv
You typed:
1234567890opqrstuv
army1987@army1987-laptop:~$
regardless of what I type between the two calls, and want the
terminal to continue working normally after the program exits.
Is there any way to do that?
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Ben Bacarisse 2007-08-21, 1:21 pm |
| Army1987 <army1987@NOSPAM.it> writes:
<snip>
> Is there a way to temporarily stop the keyboard input from going
> to stdin and from being echoed, while still augmenting
> /dev/random's entropy pool?
You need to put the tty that is connected to stdin into "raw" or "half
cooked" mode (these are old terms and may no longer apply). All
curses and termcap libraries have a "simple" way to do this (since
they need it for anything but the most basic programs).
I can probably even find some old code, if this is not enough for you
to find the interface you need.
--
Ben.
| |
| Army1987 2007-08-21, 1:21 pm |
| On Tue, 21 Aug 2007 15:53:00 +0100, Ben Bacarisse wrote:
> Army1987 <army1987@NOSPAM.it> writes:
>
> <snip>
>
> You need to put the tty that is connected to stdin into "raw" or "half
> cooked" mode (these are old terms and may no longer apply). All
> curses and termcap libraries have a "simple" way to do this (since
> they need it for anything but the most basic programs).
>
> I can probably even find some old code, if this is not enough for you
> to find the interface you need.
I've tried this:
static struct termios orig_attr;
void block_keyboard(void)
{
struct termios attr;
fsync(STDIN_FILENO);
tcgetattr(STDIN_FILENO, &orig_attr);
attr = orig_attr;
attr.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
}
void unblock_keyboard(void)
{
tcflush(STDIN_FILENO, TCIFLUSH);
fsync(STDIN_FILENO);
tcsetattr(STDIN_FILENO, TCSANOW, &orig_attr);
}
but the tcflush() call also discards characters typed *before*
block_keyboard() is called. (I hoped that the fsync() call in
block_keyboard() could help this...)
army1987@army1987-laptop:~$ cat keyblock.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
static struct termios orig_attr;
void block_keyboard(void)
{
struct termios attr;
fsync(STDIN_FILENO);
tcgetattr(STDIN_FILENO, &orig_attr);
attr = orig_attr;
attr.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
}
void unblock_keyboard(void)
{
tcflush(STDIN_FILENO, TCIFLUSH);
fsync(STDIN_FILENO);
tcsetattr(STDIN_FILENO, TCSANOW, &orig_attr);
}
int main(void)
{
int ch;
sleep(5);
fputs("keyboard blocked NOW! ", stderr);
block_keyboard();
sleep(5);
fputs("keyboard unblocked NOW! ", stderr);
unblock_keyboard();
sleep(5);
puts("You typed:");
while ((ch = getchar()) != EOF) {
putchar(ch);
}
}
army1987@army1987-laptop:~$ ./keyblock
(before) keyboard blocked NOW! keyboard unblocked NOW! (after)
You typed:
(after)
army1987@army1987-laptop:~$ diff keyblock.c keyblock1.c
21c21
< tcflush(STDIN_FILENO, TCIFLUSH);
---
> /* tcflush(STDIN_FILENO, TCIFLUSH); */
army1987@army1987-laptop:~$ ./keyblock1
(before) keyboard blocked NOW! keyboard unblocked NOW! (after)
You typed:
(before) (between) (after)
army1987@army1987-laptop:~$
How can I do to discard "(between) " but not "(before) "?
(Well, actually in the real code it is unlikely that there are
unread characters on the input stream when block_keyboard() is
called, but if there were any, is there a way to keep them?)
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Ben Bacarisse 2007-08-21, 7:24 pm |
| Army1987 <army1987@NOSPAM.it> writes:
> On Tue, 21 Aug 2007 15:53:00 +0100, Ben Bacarisse wrote:
>
> I've tried this:
> static struct termios orig_attr;
>
> void block_keyboard(void)
> {
> struct termios attr;
> fsync(STDIN_FILENO);
> tcgetattr(STDIN_FILENO, &orig_attr);
> attr = orig_attr;
> attr.c_lflag &= ~(ECHO | ICANON);
> tcsetattr(STDIN_FILENO, TCSANOW, &attr);
> }
>
> void unblock_keyboard(void)
> {
> tcflush(STDIN_FILENO, TCIFLUSH);
> fsync(STDIN_FILENO);
> tcsetattr(STDIN_FILENO, TCSANOW, &orig_attr);
> }
>
> but the tcflush() call also discards characters typed *before*
> block_keyboard() is called. (I hoped that the fsync() call in
> block_keyboard() could help this...)
<full program snipped>
> army1987@army1987-laptop:~$ ./keyblock
> (before) keyboard blocked NOW! keyboard unblocked NOW! (after)
> You typed:
> (after)
> army1987@army1987-laptop:~$ diff keyblock.c keyblock1.c
> 21c21
> < tcflush(STDIN_FILENO, TCIFLUSH);
> ---
> army1987@army1987-laptop:~$ ./keyblock1
> (before) keyboard blocked NOW! keyboard unblocked NOW! (after)
> You typed:
> (before) (between) (after)
> army1987@army1987-laptop:~$
>
> How can I do to discard "(between) " but not "(before) "?
> (Well, actually in the real code it is unlikely that there are
> unread characters on the input stream when block_keyboard() is
> called, but if there were any, is there a way to keep them?)
All I can think of is to read it first (so it does not get lost). In
other words, I'd have block_keyboard read as much data as exists on
stdin (or at least the file descriptor) and squirrel it away.
unblock_keyboard can then put it can onto the stream. Is that a
suitable method?
There *may* be some neat termios trick to do what you want, but I can't
think of it...
--
Ben.
| |
| David Schwartz 2007-08-22, 1:23 am |
| On Aug 21, 5:22 am, Army1987 <army1...@NOSPAM.it> wrote:
> I'll try to be clearer:
> I mean, if I am running a program and the input isn't redirected,
> whenever I hit a key it is echoed to the terminal emulator or
> console, and also, as soon as I hit Enter all the characters I
> type become available for reading with getchar().
> I am trying to temporarily disable this: that is, between
> block_keyboard() and unblock_keyboard() the characters typed won't
> show on the screen, and (if the input of the program isn't
> redirected) don't go to stdin, that is, a sequence of getchar()
> calls, after the last character typed before block_keyboard()
> should read the first character typed after unblock_keyboard().
> Anyway, the OS must continue to see the keyboard, so that I can
> still send signals to that program via Ctrl-C etc., I can still
> use the keyboard in other programs, etc.
> IOW, between block_keyboard() and unblock_keyboard() the program
> should behave as if the user weren't typing anything, but all the
> other processes should behave normally.
So you're simply asking how to switch a terminal into raw mode and
disable echoing? It's just very odd to me that you're asking advanced
questions about entropy collection and manipulation and don't know
something that basic.
'man 3 termios' or google 'tcsetattr' or 'cfmakeraw'.
DS
| |
| David Schwartz 2007-08-22, 1:23 am |
| On Aug 21, 10:39 am, Army1987 <army1...@NOSPAM.it> wrote:
> but the tcflush() call also discards characters typed *before*
> block_keyboard() is called. (I hoped that the fsync() call in
> block_keyboard() could help this...)
Oh, for the love of God don't do that. If you aren't in control of the
input (that is, if the user isn't talking to *you*), don't block the
keyboard. This is the cause of one of my greatest frustrations with
Windows and I'd hate to see UNIX software start doing user hostile
crap like that.
If you are going to eat my input, make god damn sure that I know that
I'm typing to you *FIRST*. That way, you will only eat your own input.
DS
| |
| Ivan Gotovchits 2007-08-22, 7:27 am |
| Army1987 wrote:
> On Tue, 21 Aug 2007 13:21:07 +0000, crox wrote:
>
> [snip]
> [signature snipped]
> It does disable echo, but it doesn't even re-enable the keyboard.
> In the example below, I typed "1234567890" before the first fputs
> to stderr, "abcdefghijk" between the two, and "opqrstuv" after the
> second one. The program did not even see the digits, and after it
> exited, not even the shell interpreted the keyboard. The only key
> which was working was Enter, which attempted to interpret all the
> former input as a command. Not even the newline before the prompt
> worked anymore.
>
> army1987@army1987-laptop:~$ cat keyblock.c
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <termios.h>
> #include <stdio.h>
>
> void block_keyboard(void)
> {
> int nd;
> struct termios attr;
> tcgetattr(STDIN_FILENO, &attr);
> attr.c_lflag &= ~ECHO;
> tcsetattr(STDIN_FILENO, TCSANOW, &attr);
> nd = open("/dev/null", O_RDWR);
> dup2(nd, STDIN_FILENO);
> close(nd);
> fsync(STDIN_FILENO);
> }
>
> void unblock_keyboard(void)
> {
> int nd;
> struct termios attr;
> tcgetattr(STDIN_FILENO, &attr);
> attr.c_lflag |= ECHO;
> tcsetattr(STDIN_FILENO, TCSANOW, &attr);
> nd = open("/dev/console", O_RDONLY);
> dup2(nd, STDIN_FILENO);
> close(nd);
> fsync(STDIN_FILENO);
> }
>
> int main(void)
> {
> int ch;
> sleep(5);
> fputs("keyboard blocked NOW! ", stderr);
> block_keyboard();
> sleep(5);
> fputs("keyboard unblocked NOW! ", stderr);
> unblock_keyboard();
> sleep(5);
> puts("You typed:");
> while ((ch = getchar()) != EOF) {
> putchar(ch);
> }
> }
> army1987@army1987-laptop:~$ cc keyblock.c -o keyblock
> army1987@army1987-laptop:~$ ./keyblock
> 1234567890keyboard blocked NOW! keyboard unblocked NOW! You typed:
> army1987@army1987-laptop:~$ bash: 1234567890abcdefghijkopqrstuv: command
> not found army1987@army1987-laptop:~$ bash: 1234567890abcdefghijkopqrstuv:
> command not found army1987@army1987-laptop:~$ army1987@army1987-laptop:~$
> army1987@army1987-laptop:~$ army1987@army1987-laptop:~$
>
> What I would expect is:
> army1987@army1987-laptop:~$ ./keyblock
> 1234567890keyboard blocked NOW! keyboard unblocked NOW! opqrstuv
> You typed:
> 1234567890opqrstuv
> army1987@army1987-laptop:~$
> regardless of what I type between the two calls, and want the
> terminal to continue working normally after the program exits.
> Is there any way to do that?
I hope that this implementation will have less bugs:
struct termios attr;
tcgetattr(STDIN_FILENO, &attr);
void block_keyboard(void)
{
int nd;
close(STDIN_FILENO);
nd = open("/dev/null", O_RDWR);
dup2(nd, STDIN_FILENO);
attr.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
close(nd);
}
void unblock_keyboard(void)
{
int nd;
fsync(STDIN_FILENO);
close(STDIN_FILENO);
nd = open("/dev/console", O_RDONLY);
dup2(nd, STDIN_FILENO);
close(nd);
attr.c_lflag |= ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
}
| |
| Ivan Gotovchits 2007-08-22, 7:27 am |
| Army1987 wrote:
> On Tue, 21 Aug 2007 04:35:13 -0700, David Schwartz wrote:
>
> I'll try to be clearer:
> I mean, if I am running a program and the input isn't redirected,
> whenever I hit a key it is echoed to the terminal emulator or
> console, and also, as soon as I hit Enter all the characters I
> type become available for reading with getchar().
> I am trying to temporarily disable this: that is, between
> block_keyboard() and unblock_keyboard() the characters typed won't
> show on the screen, and (if the input of the program isn't
> redirected) don't go to stdin, that is, a sequence of getchar()
> calls, after the last character typed before block_keyboard()
> should read the first character typed after unblock_keyboard().
> Anyway, the OS must continue to see the keyboard, so that I can
> still send signals to that program via Ctrl-C etc., I can still
> use the keyboard in other programs, etc.
> IOW, between block_keyboard() and unblock_keyboard() the program
> should behave as if the user weren't typing anything, but all the
> other processes should behave normally.
May be it is better, to use
while (1) {
getc(stdin);
}
You can implement it in another process or a thread, and create this
"keyboard eater" in block_keyboard and kill in unblock_keyboard.
Or, may be it is better to implemet your "pooleater" in another process.
And I still cannot understand what is the purpose of this actions? May be we
can found a much simplier solution if the purpose of our actions will be
known ))
As I can see, all my solutions do not follow KISS ))
| |
| Army1987 2007-08-22, 7:27 am |
| On Wed, 22 Aug 2007 12:38:51 +0400, Ivan Gotovchits wrote:
> May be it is better, to use
>
> while (1) {
> getc(stdin);
> }
>
> You can implement it in another process or a thread, and create this
> "keyboard eater" in block_keyboard and kill in unblock_keyboard.
> Or, may be it is better to implemet your "pooleater" in another process.
> And I still cannot understand what is the purpose of this actions? May be we
> can found a much simplier solution if the purpose of our actions will be
> known ))
> As I can see, all my solutions do not follow KISS ))
I am reading lots of data from /dev/random.
Reading from /dev/random stops when the entropy pool is empty. The
entropy pool is refilled with environmental noise, including the
timing of asynchronous interrupts such as keyboard ones, if I
understand correctly. So an effective way to refill the entropy
pool would be to type randomly. So what I want to do is:
#define PROMPT "Please move around the mouse and/or type randomly"
#define LEN (sizeof PROMPT - 1)
size_t fnprint(int ch, size_t n, FILE *stream)
{
register size_t result = 0;
while (n--)
if (putc(ch, stream) != EOF)
result++;
return result;
}
unsigned long getent(unsigned long *pool)
{
static FILE *randfp;
[snip]
randfp = fopen("/dev/random", "rb");
[snip]
unsigned long res;
fputs(PROMPT, stderr);
lock();
res = fread(pool, sizeof *pool, 1, randfp);
fnprint('\b', LEN, stderr);
fnprint(' ', LEN, stderr);
fnprint('\b', LEN, stderr);
unlock();
return -res; /* 0 on failure, ULONG_MAX on success */
[snip]
}
This function will be called many times.
The point is that the user could type randomly after lock()
without the program seeing this input. (Of course, other programs
should continue to work, and Ctrl-C etc. should continue to send
their signals.)
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-22, 7:27 am |
| On Tue, 21 Aug 2007 20:20:11 -0700, David Schwartz wrote:
> On Aug 21, 5:22 am, Army1987 <army1...@NOSPAM.it> wrote:
>
>
> So you're simply asking how to switch a terminal into raw mode and
> disable echoing? It's just very odd to me that you're asking advanced
> questions about entropy collection and manipulation and don't know
> something that basic.
I am not asking about entropy collection. I don't want to collect
it myself. "The random number generator gathers environmental
noise from device drivers and other sources into an entropy pool"
(man 4 random).
> 'man 3 termios' or google 'tcsetattr' or 'cfmakeraw'.
>
> DS
Unsetting the ICANON bit doesn't help.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-22, 7:27 am |
| On Tue, 21 Aug 2007 20:22:07 -0700, David Schwartz wrote:
> On Aug 21, 10:39 am, Army1987 <army1...@NOSPAM.it> wrote:
>
>
> Oh, for the love of God don't do that. If you aren't in control of the
> input (that is, if the user isn't talking to *you*), don't block the
> keyboard. This is the cause of one of my greatest frustrations with
> Windows and I'd hate to see UNIX software start doing user hostile
> crap like that.
>
> If you are going to eat my input, make god damn sure that I know that
> I'm typing to you *FIRST*. That way, you will only eat your own input.
I don't want to block the keyboard on such a low level. I just
want *my* process not to "see" the keyboard input. Other processes
should continue to work as before.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-22, 7:27 am |
| On Wed, 22 Aug 2007 12:25:43 +0400, Ivan Gotovchits wrote:
> Army1987 wrote:
>
[snip][vbcol=seagreen]
>
> I hope that this implementation will have less bugs:
>
> struct termios attr;
> tcgetattr(STDIN_FILENO, &attr);
>
> void block_keyboard(void)
> {
> int nd;
> close(STDIN_FILENO);
> nd = open("/dev/null", O_RDWR);
> dup2(nd, STDIN_FILENO);
> attr.c_lflag &= ~ECHO;
> tcsetattr(STDIN_FILENO, TCSANOW, &attr);
> close(nd);
> }
>
> void unblock_keyboard(void)
> {
> int nd;
> fsync(STDIN_FILENO);
> close(STDIN_FILENO);
> nd = open("/dev/console", O_RDONLY);
> dup2(nd, STDIN_FILENO);
> close(nd);
> attr.c_lflag |= ECHO;
> tcsetattr(STDIN_FILENO, TCSANOW, &attr);
> }
It does not disable echoing, it hides away all of the input, which
will then reappear on the prompt (and if it contains newlines, the
shell will try to interpret each line as a command).
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Ivan Gotovchits 2007-08-22, 1:23 pm |
| Army1987 wrote:
> On Wed, 22 Aug 2007 12:38:51 +0400, Ivan Gotovchits wrote:
>
> I am reading lots of data from /dev/random.
> Reading from /dev/random stops when the entropy pool is empty. The
> entropy pool is refilled with environmental noise, including the
> timing of asynchronous interrupts such as keyboard ones, if I
> understand correctly. So an effective way to refill the entropy
> pool would be to type randomly. So what I want to do is:
> #define PROMPT "Please move around the mouse and/or type randomly"
> #define LEN (sizeof PROMPT - 1)
>
> size_t fnprint(int ch, size_t n, FILE *stream)
> {
> register size_t result = 0;
> while (n--)
> if (putc(ch, stream) != EOF)
> result++;
> return result;
> }
>
> unsigned long getent(unsigned long *pool)
> {
> static FILE *randfp;
> [snip]
> randfp = fopen("/dev/random", "rb");
> [snip]
> unsigned long res;
> fputs(PROMPT, stderr);
> lock();
> res = fread(pool, sizeof *pool, 1, randfp);
> fnprint('\b', LEN, stderr);
> fnprint(' ', LEN, stderr);
> fnprint('\b', LEN, stderr);
> unlock();
> return -res; /* 0 on failure, ULONG_MAX on success */
> [snip]
> }
> This function will be called many times.
> The point is that the user could type randomly after lock()
> without the program seeing this input. (Of course, other programs
> should continue to work, and Ctrl-C etc. should continue to send
> their signals.)
Then the idea with keyboard eater can pass ...
int eater_pid;
void lock(void)
{
eater_pid = fork();
switch(eater_pid) {
case 0:
do {
getc(stdin);
}while(1);
break;
case -1:
/* error */
exit(1);
default:
return;
}
}
void unlock(void)
{
(void)kill(eater_pid, SIGTERM);
(void)waitpid(eater_pid, NULL, 0);
}
and disable echo in with `tcsetattr' if you do not want it.
| |
| Ivan Gotovchits 2007-08-22, 1:23 pm |
| Army1987 wrote:
> On Wed, 22 Aug 2007 12:38:51 +0400, Ivan Gotovchits wrote:
>
> I am reading lots of data from /dev/random.
> Reading from /dev/random stops when the entropy pool is empty. The
> entropy pool is refilled with environmental noise, including the
> timing of asynchronous interrupts such as keyboard ones, if I
> understand correctly. So an effective way to refill the entropy
> pool would be to type randomly. So what I want to do is:
> #define PROMPT "Please move around the mouse and/or type randomly"
> #define LEN (sizeof PROMPT - 1)
>
> size_t fnprint(int ch, size_t n, FILE *stream)
> {
> register size_t result = 0;
> while (n--)
> if (putc(ch, stream) != EOF)
> result++;
> return result;
> }
>
> unsigned long getent(unsigned long *pool)
> {
> static FILE *randfp;
> [snip]
> randfp = fopen("/dev/random", "rb");
> [snip]
> unsigned long res;
> fputs(PROMPT, stderr);
> lock();
> res = fread(pool, sizeof *pool, 1, randfp);
> fnprint('\b', LEN, stderr);
> fnprint(' ', LEN, stderr);
> fnprint('\b', LEN, stderr);
> unlock();
> return -res; /* 0 on failure, ULONG_MAX on success */
> [snip]
> }
> This function will be called many times.
> The point is that the user could type randomly after lock()
> without the program seeing this input. (Of course, other programs
> should continue to work, and Ctrl-C etc. should continue to send
> their signals.)
and your need to put the terminal in the raw mode, otherwise, all user's
input will be stored in the buffer and will not be passed to the "eater"
until user hits `enter'.
| |
| David Schwartz 2007-08-22, 7:23 pm |
| On Aug 22, 2:34 am, Army1987 <army1...@NOSPAM.it> wrote:
> want *my* process not to "see" the keyboard input. Other processes
> should continue to work as before.
Then just throw the input away.
DS
| |
| Army1987 2007-08-22, 7:23 pm |
| On Wed, 22 Aug 2007 17:08:04 +0400, Ivan Gotovchits wrote:
> Army1987 wrote:
>
> and your need to put the terminal in the raw mode, otherwise, all user's
> input will be stored in the buffer and will not be passed to the "eater"
> until user hits `enter'.
Even so, it also discards input typed *before* lock(). This is
almost acceptable, but I prefer the solution with tcflush() I
posted elsethread to do this.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-22, 7:23 pm |
| On Wed, 22 Aug 2007 12:54:09 -0700, David Schwartz wrote:
> On Aug 22, 2:34 am, Army1987 <army1...@NOSPAM.it> wrote:
>
>
> Then just throw the input away.
>
> DS
Is there any way to write two functions, let's say lock() and
unlock(), so that I can throw away the input typed between the
moment lock() is called and the moment unlock() is called? I've
tried to use fsync() in lock() and tcflush() in unlock(), but the
input typed before lock() is discarded, too.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Scott Lurndal 2007-08-22, 7:23 pm |
| Army1987 <army1987@NOSPAM.it> writes:
>On Wed, 22 Aug 2007 12:54:09 -0700, David Schwartz wrote:
>
>Is there any way to write two functions, let's say lock() and
>unlock(), so that I can throw away the input typed between the
>moment lock() is called and the moment unlock() is called? I've
>tried to use fsync() in lock() and tcflush() in unlock(), but the
>input typed before lock() is discarded, too.
I guess I'd go back and question your basic assumptions.
1) Do you need to use /dev/random, or will /dev/urandom be sufficient?
urandom won't block due to lack of entropy and the results won't
be _as_ random (good enough for a simulation, perhaps not good enough
for crypto).
2) Is your application running in a shell context, within a gnome_terminal,
xterm, rxvt, screen or on a virtual terminal? If there is a graphical
desktop running, mouse activity will add to entropy, yet keyboard input
doesn't need to be delivered to the window for your application to increase
entropy.
3) Are there other methods of generating entropy if you must use /dev/random?
Even disk I/O generates entropy. Use a PRNG to generate random disk I/O
to a large file.
I don't think you can do what you want with the keyboard and get reasonable
user-visible behavior.
scott
| |
| Army1987 2007-08-23, 7:21 am |
| On Wed, 22 Aug 2007 23:50:54 +0000, Scott Lurndal wrote:
> Army1987 <army1987@NOSPAM.it> writes:
>
> I guess I'd go back and question your basic assumptions.
>
> 1) Do you need to use /dev/random, or will /dev/urandom be sufficient?
> urandom won't block due to lack of entropy and the results won't
> be _as_ random (good enough for a simulation, perhaps not good enough
> for crypto).
Yes, I know about /dev/urandom, but I'd prefer *really* random
numbers if possible.
> 2) Is your application running in a shell context, within a
> gnome_terminal,
> xterm, rxvt, screen or on a virtual terminal? If there is a
> graphical desktop running, mouse activity will add to entropy, yet
> keyboard input doesn't need to be delivered to the window for your
> application to increase entropy.
Yes, that's what I was trying to do. But asking the user to
unselect the terminal window and to type randomly "elsewhere"
didn't seem very "elegant" to me. Also, the application could be
run on a console (such as the ones I get with Ctrl-Alt-F1 through
Ctrl-Alt-F6 on Ubuntu).
> 3) Are there other methods of generating entropy if you must use
> /dev/random?
> Even disk I/O generates entropy. Use a PRNG to generate random
> disk I/O to a large file.
Good idea, I'll try that.
> I don't think you can do what you want with the keyboard and get
> reasonable user-visible behavior.
Well, I'll resort to other ways.
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| David Schwartz 2007-08-23, 7:21 am |
| On Aug 23, 2:54 am, Army1987 <army1...@NOSPAM.it> wrote:
> Yes, that's what I was trying to do. But asking the user to
> unselect the terminal window and to type randomly "elsewhere"
> didn't seem very "elegant" to me. Also, the application could be
> run on a console (such as the ones I get with Ctrl-Alt-F1 through
> Ctrl-Alt-F6 on Ubuntu).
I guess I don't understand your scenario still. Is the user actually
using your program at the time? If so, why can't you just throw away
keyboard input the same way you would process keyboard input? And if
the user has not specifically selected your application, throwing away
keyboard input is going to infuriate them.
What is the third case that you are in where you don't have focus but
find it okay to throw away keypresses?
DS
| |
| Army1987 2007-08-23, 1:27 pm |
| On Thu, 23 Aug 2007 04:34:02 -0700, David Schwartz wrote:
> On Aug 23, 2:54 am, Army1987 <army1...@NOSPAM.it> wrote:
>
>
> I guess I don't understand your scenario still. Is the user actually
> using your program at the time? If so, why can't you just throw away
> keyboard input the same way you would process keyboard input?
What I needed was:
fputs("Please type randomly:\n", stderr);
lock_keyboard();
fread(pool, sizeof *pool, 1, randfp);
fputs("\b\b\b" /* etc. */ " " /* etc. */ "\b\b\b", stderr);
unlock_keyboard();
I can't find a way to discard the input typed after lock_keyboard
but not the one typed before it. (But now that Scott suggested me
not to do that and write to disk so that /dev/random can gather
entropy from the disk driver, I don't need that anymore.)
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Army1987 2007-08-23, 1:27 pm |
| On Wed, 22 Aug 2007 23:50:54 +0000, Scott Lurndal wrote:
> 3) Are there other methods of generating entropy if you must use /dev/random?
> Even disk I/O generates entropy. Use a PRNG to generate random disk I/O
> to a large file.
Thank you. This isn't very fast, but it works:
static pid_t pid;
static void refill(void)
{
FILE *tmp;
srand(time(NULL));
switch (pid = fork()) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
tmp = tmpfile();
if (tmp == NULL) { perror("tmpfile"); exit(EXIT_FAILURE); }
setbuf(tmp, NULL);
for (;;) {
int rn = rand();
fwrite(&rn, sizeof rn, 1, tmp);
}
default:
return;
}
}
static void end_refill(void) { kill(pid, SIGTERM); wait(NULL); }
unsigned long getent(unsigned long *pool)
{
/*...*/
refill();
res = fread(pool, sizeof *pool, 1, randfp);
end_refill();
/*...*/
}
--
Army1987 (Replace "NOSPAM" with "email")
No-one ever won a game by resigning. -- S. Tartakower
| |
| Scott Lurndal 2007-08-23, 1:27 pm |
| Army1987 <army1987@NOSPAM.it> writes:
>On Wed, 22 Aug 2007 23:50:54 +0000, Scott Lurndal wrote:
>
>Yes, I know about /dev/urandom, but I'd prefer *really* random
>numbers if possible.
Unless you're doing cryptographic key generation, the difference in
randomness between /dev/random and /dev/urandom is insignificant.
scott
|
|
|
|
|