'Inappropriate ioctl for device' error in C

c, getch

Solution

This is probably because Eclipse is not providing a pseudoterminal to programs run under the IDE. Try this alternative which relies on nonblocking I/O rather than terminal controls.

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define perror_exit(msg) do { perror(msg); exit(1); } while(0)

#if defined EAGAIN && defined EWOULDBLOCK
#define retry_p(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
#elif defined EAGAIN
#define retry_p(err) ((err) == EAGAIN)
#elif defined EWOULDBLOCK
#define retry_p(err) ((err) == EWOULDBLOCK)
#else
#error "Don't know how to detect read-would-block condition."
#endif

int
main(void)
{
    int flags = fcntl(0, F_GETFL);
    if (flags == -1)
        perror_exit("fcntl(F_GETFL)");
    flags |= O_NONBLOCK;
    if (fcntl(0, F_SETFL, flags))
        perror_exit("fcntl(F_SETFL, O_NONBLOCK)");

    for (;;)
    {
       char ch;
       ssize_t n = read(0, &ch, 1);
       if (n == 1)
       {
           putchar(ch);
           if (ch == 'q')
               break;
       }
       else if (n < 0 && !retry_p(errno))
          perror_exit("read");
    }
    return 0;
}

If this still doesn't work, try modifying it to do both what this does and what your `getch()` does, ignoring failure of `tcsetattr` and `tcgetattr` when `errno == ENOTTY`.

Note that both this and your original code are busy-waiting for I/O, which is bad practice. What you really should be doing is using the ncurses library, which has a more sophisticated approach to simultaneous processing and waiting for input that fits better with a multitasking environment, and also deals with your lack-of-a-tty problem and any number of other low-level headaches that you don't want to waste effort on.

Problem

I have a `getch()` function which my tutor gave me, which is getting input from the keyboard without clicking on 'ENTER'. But, when I run it in Ubuntu 12 in Eclipse, I get the following error: ``` tcsetattr(): Inappropriate ioctl for device tcsetattr ICANON: Inappropriate ioctl for device ``` This is my code: ``` #include <stdio.h> #include <unistd.h> #include <termios.h> char getch(); int main(int argc, const char* argv[]) { char c; do { c=getch(); printf("%c",c); } while(c!='q'); return 0; } char getch() { char buf = 0; struct termios old = {0}; if (tcgetattr(0, &old) < 0) perror("tcsetattr()"); old.c_lflag &= ~ICANON; old.c_lflag &= ~ECHO; old.c_cc[VMIN] = 1; old.c_cc[VTIME] = 0; if (tcsetattr(0, TCSANOW, &old) < 0) perror("tcsetattr ICANON"); if (read(0, &buf, 1) < 0) perror ("read()"); old.c_lflag |= ICANON; old.c_lflag |= ECHO; if (tcsetattr(0, TCSADRAIN, &old) < 0) perror ("tcsetattr ~ICANON"); return (buf); } ``` NOTE: The code DOES work in SSH Secure Shell. But I have to get this work in my Ubuntu, since I write my code there. Thanks

Original source