1 /* $Id: irpty.c,v 5.12 2007/01/16 05:11:11 lirc Exp $ */
3 /****************************************************************************
4 ** irpty.c *****************************************************************
5 ****************************************************************************
7 * irpty - pseudo tty driver
8 * Connects to lircd via socket to receive infra-red codes
9 * and converts them to key strokes
11 * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
12 * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
34 #include <sys/types.h>
39 #if defined (__APPLE__) || defined (__NetBSD__)
42 #if defined (__FreeBSD__)
50 #include "lirc_client.h"
54 const char *progname
="irpty";
56 struct lirc_config
*lconfig
;
58 static int lsock
, sigcaught
;
60 void die(char *fmt
,...)
65 vfprintf(stderr
, fmt
, args
);
66 lirc_freeconfig(lconfig
);
71 static void sig_term(int sig
)
77 static void copy_loop(int ptym
, int ignoreeof
)
84 if ((child
= fork()) < 0) {
91 FD_SET(STDIN_FILENO
, &fds
);
92 select(lsock
+ 1, &fds
, NULL
, NULL
, NULL
);
94 if (FD_ISSET(STDIN_FILENO
, &fds
)) {
95 if ((nread
= read(STDIN_FILENO
, buf
, BUFFSIZE
)) < 0)
96 die("read error from stdin");
99 if (write(ptym
, buf
, nread
) != nread
)
100 die("writen error to master pty");
102 if (FD_ISSET(lsock
, &fds
))
108 while((ret
=lirc_nextcode(&ir
))==0)
111 while((ret
=lirc_code2char
112 (lconfig
,ir
,&irchars
))==0 &&
115 if(write(ptym
,irchars
,strlen(irchars
)) != strlen(irchars
))
116 die("writen error to master pty");
125 kill(getppid(), SIGTERM
);
126 lirc_freeconfig(lconfig
);
131 act
.sa_handler
=sig_term
;
132 sigemptyset(&act
.sa_mask
);
133 act
.sa_flags
=0; /* we need EINTR */
134 sigaction(SIGTERM
,&act
,NULL
);
137 if ((nread
= read(ptym
, buf
, BUFFSIZE
)) <= 0)
139 if (write(STDOUT_FILENO
, buf
, nread
) != nread
)
140 die("writen error to stdout");
143 kill(child
, SIGTERM
);
144 lirc_freeconfig(lconfig
);
149 static struct termios save_termios
;
150 static int ttysavefd
= -1;
159 if (tcgetattr(fd
, &save_termios
) < 0)
163 buf
.c_lflag
&= ~(ECHO
| ICANON
| IEXTEN
| ISIG
);
164 buf
.c_iflag
&= ~(BRKINT
| ICRNL
| INPCK
| ISTRIP
| IXON
);
165 buf
.c_cflag
&= ~(CSIZE
| PARENB
);
167 buf
.c_oflag
&= ~(OPOST
);
171 if (tcsetattr(fd
, TCSAFLUSH
, &buf
) < 0)
178 int tty_reset(int fd
)
180 if (ttystate
!= CBREAK
&& ttystate
!= RAW
)
182 if (tcsetattr(fd
, TCSAFLUSH
, &save_termios
) < 0)
188 void tty_atexit(void)
191 tty_reset(ttysavefd
);
196 #define pty_fork(ptrfdm, slave_name, slave_termios, slave_winsize) \
197 forkpty(ptrfdm, slave_name, slave_termios, slave_winsize)
200 /* Open the next free pty */
202 int pty_open(char *pty_name
)
207 strcpy(pty_name
, "/dev/ptyp0");
208 for (ptr1
= "pqrstuvwxyzabcde"; *ptr1
; ptr1
++) {
210 for (ptr2
= "0123456789abcdef"; *ptr2
; ptr2
++) {
213 if ((fd
= open(pty_name
, O_RDWR
)) >= 0) {
216 } else if (errno
== ENOENT
)
223 int tty_open(int fdm
, char *tty_name
)
228 if ((grptr
= getgrnam("tty")) != NULL
)
234 chown(tty_name, getuid(), gid);
235 chmod(tty_name, S_IRUSR | S_IWUSR | S_IWGRP);
238 if ((fds
= open(tty_name
, O_RDWR
)) < 0) {
245 pid_t
pty_fork(int *ptrfdm
, char *slave_name
,
246 struct termios
* slave_termios
,
247 struct winsize
* slave_winsize
)
253 if ((fdm
= pty_open(pts_name
)) < 0)
254 die("can't open pty %s\n",pts_name
);
256 strcpy(slave_name
, pts_name
);
258 if ((pid
= fork()) < 0)
263 if ((fds
= tty_open(fdm
, pts_name
)) < 0)
264 die("can't open slave pty %s\n",pts_name
);
268 if (tcsetattr(fds
, TCSANOW
, slave_termios
) < 0)
269 die("tcsetattr error on slave pty");
272 if (ioctl(fds
, TIOCSWINSZ
, slave_winsize
) < 0)
273 die("TIOCSWINSZ error on slave pty");
275 if (dup2(fds
, STDIN_FILENO
) != STDIN_FILENO
)
276 die("dup2 error to stdin");
277 if (dup2(fds
, STDOUT_FILENO
) != STDOUT_FILENO
)
278 die("dup2 error to stdout");
279 if (dup2(fds
, STDERR_FILENO
) != STDERR_FILENO
)
280 die("dup2 error to stderr");
281 if (fds
> STDERR_FILENO
)
290 static void set_noecho(int fd
)
292 struct termios stermios
;
294 if (tcgetattr(fd
, &stermios
) < 0)
295 die("tcgetattr error");
296 stermios
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
297 stermios
.c_oflag
&= ~(ONLCR
);
298 if (tcsetattr(fd
, TCSANOW
, &stermios
) < 0)
299 die("tcsetattr error");
302 static struct option long_options
[] =
304 {"help",no_argument
,NULL
,'h'},
305 {"version",no_argument
,NULL
,'V'},
306 {"socket",required_argument
,NULL
,'s'},
307 {"no-echo",no_argument
,NULL
,'e'},
308 {"ignore-eof",no_argument
,NULL
,'i'},
309 {"non-interactive",no_argument
,NULL
,'n'},
310 {"verbose",no_argument
,NULL
,'v'},
314 int main(int argc
, char *argv
[])
316 int fdm
, c
, ignoreeof
, interactive
, noecho
, verbose
;
318 char *config
, slave_name
[20];
319 struct termios orig_termios
;
323 interactive
= isatty(STDIN_FILENO
);
329 while ((c
= getopt_long(argc
, argv
, "hVs:einv",long_options
,NULL
))
333 printf("Usage: %s [options] config_file -- "
334 "program [args ...]\n",argv
[0]);
335 printf("\t -h --help \t\tdisplay usage summary\n");
336 printf("\t -V --version \t\tdisplay version\n");
337 printf("\t -e --no-echo \t\tdisable echo\n");
338 printf("\t -i --ignore-eof \tignore EOF\n");
339 printf("\t -n --non-interactive \tforce non-interactive mode\n");
340 printf("\t -v --verbose \t\tverbose mode\n");
341 return(EXIT_SUCCESS
);
343 printf("%s %s\n", progname
, VERSION
);
344 return(EXIT_SUCCESS
);
363 die("unrecognized option: -%c\n", optopt
);
366 if (optind
+ 1 >= argc
)
367 die("usage: irpty [ -s server -einv ] cfg program [ arg ... ]\n");
369 config
= argv
[optind
++];
371 if((lsock
=lirc_init("irpty",1))==-1) exit(EXIT_FAILURE
);
372 flags
=fcntl(lsock
,F_GETFL
,0);
375 fcntl(lsock
,F_SETFL
,flags
|FASYNC
|O_NONBLOCK
);
378 if(lirc_readconfig(config
,&lconfig
,NULL
)!=0) exit(EXIT_FAILURE
);
381 if (tcgetattr(STDIN_FILENO
, &orig_termios
) < 0)
382 die("tcgetattr error on stdin\n");
383 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, (char *) &size
) < 0)
384 die("TIOCGWINSZ error\n");
385 pid
= pty_fork(&fdm
, slave_name
, &orig_termios
, &size
);
387 pid
= pty_fork(&fdm
, slave_name
, NULL
, NULL
);
391 else if (!pid
) { /* child */
393 set_noecho(STDIN_FILENO
); /* stdin is slave pty */
394 if (execvp(argv
[optind
], &argv
[optind
]) < 0)
395 die("can't execute: %s\n", argv
[optind
]);
398 fprintf(stderr
, "slave name = %s\n", slave_name
);
400 fprintf(stderr
, "config file = %s\n", config
);
403 if (tty_raw(STDIN_FILENO
) < 0) /* user's tty to raw mode */
404 die("tty_raw error");
405 if (atexit(tty_atexit
) < 0) /* reset user's tty on exit */
408 copy_loop(fdm
, ignoreeof
);