Little fix.
[irreco.git] / lirc-0.8.4a / tools / irpty.c
blob06aba68c9a71331d0d7e47b9432a349d686eb76f
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>
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <grp.h>
24 #include <signal.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <termios.h>
36 #include <unistd.h>
38 #ifdef HAVE_FORKPTY
39 #if defined (__APPLE__) || defined (__NetBSD__)
40 #include <util.h>
41 #else
42 #if defined (__FreeBSD__)
43 #include <libutil.h>
44 #else
45 #include <pty.h>
46 #endif
47 #endif
48 #endif
50 #include "lirc_client.h"
52 #define BUFFSIZE 512
54 const char *progname="irpty";
56 struct lirc_config *lconfig;
58 static int lsock, sigcaught;
60 void die(char *fmt,...)
62 va_list args;
64 va_start(args, fmt);
65 vfprintf(stderr, fmt, args);
66 lirc_freeconfig(lconfig);
67 lirc_deinit();
68 exit(1);
71 static void sig_term(int sig)
73 sigcaught = 1;
74 return;
77 static void copy_loop(int ptym, int ignoreeof)
79 pid_t child;
80 int nread;
81 char buf[BUFFSIZE];
82 struct sigaction act;
84 if ((child = fork()) < 0) {
85 die("fork error");
86 } else if (!child) {
87 fd_set fds;
88 while (1) {
89 FD_ZERO(&fds);
90 FD_SET(lsock, &fds);
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");
97 else if (!nread)
98 break;
99 if (write(ptym, buf, nread) != nread)
100 die("writen error to master pty");
102 if (FD_ISSET(lsock, &fds))
104 char *ir;
105 char *irchars;
106 int ret;
108 while((ret=lirc_nextcode(&ir))==0)
110 if(ir==NULL) break;
111 while((ret=lirc_code2char
112 (lconfig,ir,&irchars))==0 &&
113 irchars!=NULL)
115 if(write(ptym,irchars,strlen(irchars)) != strlen(irchars))
116 die("writen error to master pty");
118 free(ir);
119 if(ret==-1) break;
121 if(ret==-1) break;
124 if (!ignoreeof)
125 kill(getppid(), SIGTERM);
126 lirc_freeconfig(lconfig);
127 lirc_deinit();
128 _exit(0);
131 act.sa_handler=sig_term;
132 sigemptyset(&act.sa_mask);
133 act.sa_flags=0; /* we need EINTR */
134 sigaction(SIGTERM,&act,NULL);
136 while (1) {
137 if ((nread = read(ptym, buf, BUFFSIZE)) <= 0)
138 break;
139 if (write(STDOUT_FILENO, buf, nread) != nread)
140 die("writen error to stdout");
142 if (!sigcaught)
143 kill(child, SIGTERM);
144 lirc_freeconfig(lconfig);
145 lirc_deinit();
146 return;
149 static struct termios save_termios;
150 static int ttysavefd = -1;
151 static enum {
152 RESET, RAW, CBREAK
153 } ttystate = RESET;
155 int tty_raw(int fd)
157 struct termios buf;
159 if (tcgetattr(fd, &save_termios) < 0)
160 return (-1);
162 buf = save_termios;
163 buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
164 buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
165 buf.c_cflag &= ~(CSIZE | PARENB);
166 buf.c_cflag |= CS8;
167 buf.c_oflag &= ~(OPOST);
168 buf.c_cc[VMIN] = 1;
169 buf.c_cc[VTIME] = 0;
171 if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
172 return (-1);
173 ttystate = RAW;
174 ttysavefd = fd;
175 return (0);
178 int tty_reset(int fd)
180 if (ttystate != CBREAK && ttystate != RAW)
181 return (0);
182 if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
183 return (-1);
184 ttystate = RESET;
185 return (0);
188 void tty_atexit(void)
190 if (ttysavefd >= 0)
191 tty_reset(ttysavefd);
194 #ifdef HAVE_FORKPTY
196 #define pty_fork(ptrfdm, slave_name, slave_termios, slave_winsize) \
197 forkpty(ptrfdm, slave_name, slave_termios, slave_winsize)
199 #else
200 /* Open the next free pty */
202 int pty_open(char *pty_name)
204 char *ptr1, *ptr2;
205 int fd;
207 strcpy(pty_name, "/dev/ptyp0");
208 for (ptr1 = "pqrstuvwxyzabcde"; *ptr1; ptr1++) {
209 pty_name[8] = *ptr1;
210 for (ptr2 = "0123456789abcdef"; *ptr2; ptr2++) {
211 pty_name[9] = *ptr2;
213 if ((fd = open(pty_name, O_RDWR)) >= 0) {
214 pty_name[5] = 't';
215 return (fd);
216 } else if (errno == ENOENT)
217 return (-1);
220 return (-1);
223 int tty_open(int fdm, char *tty_name)
225 struct group *grptr;
226 int gid, fds;
228 if ((grptr = getgrnam("tty")) != NULL)
229 gid = grptr->gr_gid;
230 else
231 gid = -1;
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) {
239 close(fdm);
240 return (-1);
242 return (fds);
245 pid_t pty_fork(int *ptrfdm, char *slave_name,
246 struct termios * slave_termios,
247 struct winsize * slave_winsize)
249 int fdm, fds;
250 pid_t pid;
251 char pts_name[20];
253 if ((fdm = pty_open(pts_name)) < 0)
254 die("can't open pty %s\n",pts_name);
255 if (slave_name)
256 strcpy(slave_name, pts_name);
258 if ((pid = fork()) < 0)
259 die("fork error\n");
260 if (!pid) {
261 if (setsid() < 0)
262 die("setsid error");
263 if ((fds = tty_open(fdm, pts_name)) < 0)
264 die("can't open slave pty %s\n",pts_name);
265 close(fdm);
267 if (slave_termios) {
268 if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
269 die("tcsetattr error on slave pty");
271 if (slave_winsize) {
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)
282 close(fds);
283 return (0);
285 *ptrfdm = fdm;
286 return (pid);
288 #endif
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'},
311 {0, 0, 0, 0}
314 int main(int argc, char *argv[])
316 int fdm, c, ignoreeof, interactive, noecho, verbose;
317 pid_t pid;
318 char *config, slave_name[20];
319 struct termios orig_termios;
320 struct winsize size;
321 int flags;
323 interactive = isatty(STDIN_FILENO);
324 ignoreeof = 0;
325 noecho = 0;
326 verbose = 0;
327 config = NULL;
329 while ((c = getopt_long(argc, argv, "hVs:einv",long_options,NULL))
330 != EOF) {
331 switch (c) {
332 case 'h':
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);
342 case 'V':
343 printf("%s %s\n", progname, VERSION);
344 return(EXIT_SUCCESS);
346 case 'e':
347 noecho = 1;
348 break;
350 case 'i':
351 ignoreeof = 1;
352 break;
354 case 'n':
355 interactive = 0;
356 break;
358 case 'v':
359 verbose = 1;
360 break;
362 case '?':
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);
373 if(flags!=-1)
375 fcntl(lsock,F_SETFL,flags|FASYNC|O_NONBLOCK);
378 if(lirc_readconfig(config,&lconfig,NULL)!=0) exit(EXIT_FAILURE);
380 if (interactive) {
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);
386 } else
387 pid = pty_fork(&fdm, slave_name, NULL, NULL);
389 if (pid < 0)
390 die("fork error\n");
391 else if (!pid) { /* child */
392 if (noecho)
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]);
397 if (verbose) {
398 fprintf(stderr, "slave name = %s\n", slave_name);
399 if (config)
400 fprintf(stderr, "config file = %s\n", config);
402 if (interactive) {
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 */
406 die("atexit error");
408 copy_loop(fdm, ignoreeof);
410 exit(0);