1 /* $Id: lircrcd.c,v 5.3 2006/05/06 09:40:07 lirc Exp $ */
3 /****************************************************************************
4 ** lircrcd.c ***************************************************************
5 ****************************************************************************
7 * lircrcd - daemon that manages current mode for all applications
9 * Copyright (C) 2004 Christoph Bartelmus <lirc@bartelmus.de>
29 #include <sys/socket.h>
32 #include <sys/types.h>
35 #include "lirc_client.h"
37 #define MAX_CLIENTS 100
38 #define PACKET_SIZE (256)
39 #define WHITE_SPACE " \t"
44 struct config_info
*next
;
50 struct config_info
*first
;
51 struct event_info
*next
;
58 struct event_info
*first_event
;
62 struct protocol_directive
65 int (*function
)(int fd
,char *message
,char *arguments
);
68 static int code_func(int fd
,char *message
,char *arguments
);
69 static int ident_func(int fd
,char *message
,char *arguments
);
70 static int getmode_func(int fd
,char *message
,char *arguments
);
71 static int setmode_func(int fd
,char *message
,char *arguments
);
72 static int send_result(int fd
, char *message
, const char *result
);
73 static int send_success(int fd
,char *message
);
75 struct protocol_directive directives
[] =
79 {"GETMODE",getmode_func
},
80 {"SETMODE",setmode_func
},
84 {"DEBUG_LEVEL",debug_level},
88 enum protocol_string_num
{
97 char *protocol_string
[] =
110 #define LOGPRINTF(level,fmt,args...) \
111 if(level<=debug) logprintf(LOG_DEBUG,fmt, ## args )
112 #define LOGPERROR(level,s) \
113 if(level<=debug) logperror(LOG_DEBUG,s)
115 #define LOGPRINTF(level,fmt,args...) \
117 #define LOGPERROR(level,s) \
121 #define logprintf syslog
122 #define logperror(prio,s) if((s)!=NULL) syslog(prio,"%s: %m\n",(char *) s); else syslog(prio,"%m\n")
124 const char *progname
="lircrcd";
126 static sig_atomic_t term
=0;
129 static struct client_data clis
[MAX_CLIENTS
];
131 static int daemonized
=0;
133 static struct lirc_config
*config
;
135 static int send_error(int fd
,char *message
,char *format_str
, ...);
136 static int handle_input();
138 static inline int max(int a
,int b
)
143 static int get_client_index(int fd
)
147 for(i
=0; i
<clin
; i
++)
154 /* shouldn't ever happen */
158 /* cut'n'paste from fileutils-3.16: */
160 #define isodigit(c) ((c) >= '0' && (c) <= '7')
162 /* Return a positive integer containing the value of the ASCII
163 octal number S. If S is not an octal number, return -1. */
173 for (i
= 0; isodigit (*s
); ++s
)
174 i
= i
* 8 + *s
- '0';
180 /* A safer write(), since sockets might not write all but only some of the
183 inline int write_socket(int fd
, char *buf
, int len
)
189 done
=write(fd
,buf
,todo
);
190 if(done
<=0) return(done
);
197 inline int write_socket_len(int fd
, char *buf
)
202 if(write_socket(fd
,buf
,len
)<len
) return(0);
206 inline int read_timeout(int fd
,char *buf
,int len
,int timeout
)
217 /* CAVEAT: (from libc documentation)
218 Any signal will cause `select' to return immediately. So if your
219 program uses signals, you can't rely on `select' to keep waiting
220 for the full time specified. If you want to be sure of waiting
221 for a particular amount of time, you must check for `EINTR' and
222 repeat the `select' with a newly calculated timeout based on the
223 current time. See the example below.
225 Obviously the timeout is not recalculated in the example because
226 this is done automatically on Linux systems...
231 ret
=select(fd
+1,&fds
,NULL
,NULL
,&tv
);
233 while(ret
==-1 && errno
==EINTR
);
236 logprintf(LOG_ERR
,"select() failed");
237 logperror(LOG_ERR
,NULL
);
240 else if(ret
==0) return(0); /* timeout */
244 logprintf(LOG_ERR
,"read() failed");
245 logperror(LOG_ERR
,NULL
);
251 static void sigterm(int sig
)
253 /* all signals are blocked now */
259 static void nolinger(int sock
)
261 static struct linger linger
= {0, 0};
262 int lsize
= sizeof(struct linger
);
263 setsockopt(sock
, SOL_SOCKET
, SO_LINGER
, (void *)&linger
, lsize
);
266 static void free_config_info(struct config_info
*ci
)
268 struct config_info
*next
;
272 if(ci
->config_string
!= NULL
) free(ci
->config_string
);
280 static void free_event_info(struct event_info
*ei
)
282 struct event_info
*next
;
286 if(ei
->code
!= NULL
) free(ei
->code
);
288 free_config_info(ei
->first
);
296 static void remove_client(int i
)
298 shutdown(clis
[i
].fd
,2);
300 if(clis
[i
].ident_string
) free(clis
[i
].ident_string
);
301 if(clis
[i
].pending_code
) free(clis
[i
].pending_code
);
302 free_event_info(clis
[i
].first_event
);
304 LOGPRINTF(1, "removed client");
313 void add_client(int sock
)
317 struct sockaddr client_addr
;
320 clilen
=sizeof(client_addr
);
321 fd
=accept(sock
,(struct sockaddr
*)&client_addr
,&clilen
);
324 logprintf(LOG_ERR
,"accept() failed for new client");
325 logperror(LOG_ERR
,NULL
);
329 if(fd
>=FD_SETSIZE
|| clin
>=MAX_CLIENTS
)
331 logprintf(LOG_ERR
,"connection rejected");
337 flags
=fcntl(fd
,F_GETFL
,0);
340 fcntl(fd
,F_SETFL
,flags
|O_NONBLOCK
);
342 LOGPRINTF(1, "accepted new client");
344 clis
[clin
].ident_string
= NULL
;
345 clis
[clin
].first_event
= NULL
;
346 clis
[clin
].pending_code
= NULL
;
350 static int opensocket(const char *configfile
, const char *socketname
,
351 mode_t permission
, struct sockaddr_un
*addr
)
358 /* get socket name */
359 if((socketname
==NULL
&&
360 lirc_getsocketname(configfile
,
361 addr
->sun_path
, sizeof(addr
->sun_path
)) >
362 sizeof(addr
->sun_path
)) ||
364 strlen(socketname
)>=sizeof(addr
->sun_path
)))
366 fprintf(stderr
, "%s: filename too long", progname
);
371 strcpy(addr
->sun_path
, socketname
);
375 sockfd
=socket(AF_UNIX
,SOCK_STREAM
,0);
378 fprintf(stderr
,"%s: could not create socket\n",progname
);
384 get owner, permissions, etc.
385 so new socket can be the same since we
386 have to delete the old socket.
388 ret
=stat(addr
->sun_path
, &s
);
389 if(ret
==-1 && errno
!=ENOENT
)
391 fprintf(stderr
,"%s: could not get file information for %s\n",
392 progname
, addr
->sun_path
);
394 goto opensocket_failed
;
400 ret
=unlink(addr
->sun_path
);
403 fprintf(stderr
,"%s: could not delete %s\n",
404 progname
, addr
->sun_path
);
406 goto opensocket_failed
;
410 addr
->sun_family
=AF_UNIX
;
411 if(bind(sockfd
, (struct sockaddr
*) addr
, sizeof(*addr
))==-1)
413 fprintf(stderr
,"%s: could not assign address to socket\n",
416 goto opensocket_failed
;
420 chmod(addr
->sun_path
, permission
):
421 (chmod(addr
->sun_path
, s
.st_mode
)==-1 ||
422 chown(addr
->sun_path
, s
.st_uid
, s
.st_gid
)==-1)
425 fprintf(stderr
,"%s: could not set file permissions\n",
428 goto opensocket_failed
;
441 static int code_func(int fd
,char *message
,char *arguments
)
444 struct event_info
*ei
;
445 struct config_info
*ci
;
448 index
= get_client_index(fd
);
451 return send_error(fd
, message
, "identify yourself first!\n");
453 if(clis
[index
].pending_code
!= NULL
)
455 return send_error(fd
, message
, "protocol error\n");
458 LOGPRINTF(3, "%s asking for code -%s-",
459 clis
[index
].ident_string
, arguments
);
461 ei
= clis
[index
].first_event
;
464 LOGPRINTF(3, "compare: -%s- -%s-", ei
->code
, arguments
);
465 if(strcmp(ei
->code
, arguments
) == 0)
471 LOGPRINTF(3, "result: -%s-",
473 ret
= send_result(fd
, message
,
475 ei
->first
= ci
->next
;
476 free(ci
->config_string
);
482 clis
[index
].first_event
= ei
->next
;
485 return send_success(fd
, message
);
490 return send_success(fd
, message
);
494 clis
[index
].pending_code
= strdup(arguments
);
495 if(clis
[index
].pending_code
== NULL
)
497 return send_error(fd
, message
, "out of memory\n");
502 static int ident_func(int fd
,char *message
,char *arguments
)
506 if(arguments
== NULL
)
508 return send_error(fd
, message
, "protocol error\n");
510 LOGPRINTF(2, "IDENT %s", arguments
);
511 index
= get_client_index(fd
);
512 if(clis
[index
].ident_string
!= NULL
)
514 return send_error(fd
, message
, "protocol error\n");
516 clis
[index
].ident_string
= strdup(arguments
);
517 if(clis
[index
].ident_string
== NULL
)
519 return send_error(fd
, message
, "out of memory\n");
522 LOGPRINTF(1, "%s connected", clis
[index
].ident_string
);
523 return(send_success(fd
,message
));
526 static int getmode_func(int fd
,char *message
,char *arguments
)
528 if(arguments
!= NULL
)
530 return send_error(fd
, message
, "protocol error\n");
532 LOGPRINTF(2, "GETMODE");
533 if(lirc_getmode(config
))
535 return send_result(fd
, message
, lirc_getmode(config
));
537 return(send_success(fd
,message
));
540 static int setmode_func(int fd
,char *message
,char *arguments
)
542 const char *mode
= NULL
;
544 LOGPRINTF(2, arguments
!=NULL
? "SETMODE %s":"SETMODE", arguments
);
545 if((mode
= lirc_setmode(config
, arguments
)))
547 return send_result(fd
, message
, mode
);
549 return arguments
==NULL
?
550 send_success(fd
,message
):
551 send_error(fd
, message
, "out of memory\n");
554 static int send_result(int fd
, char *message
, const char *result
)
557 char buffer
[strlen(result
)+1+1];
559 sprintf(buffer
, "%s\n", result
);
561 if(!(write_socket_len(fd
,protocol_string
[P_BEGIN
]) &&
562 write_socket_len(fd
,message
) &&
563 write_socket_len(fd
,protocol_string
[P_SUCCESS
]) &&
564 write_socket_len(fd
,protocol_string
[P_DATA
]) &&
565 write_socket_len(fd
,count
) &&
566 write_socket_len(fd
,buffer
) &&
567 write_socket_len(fd
,protocol_string
[P_END
]))) return(0);
571 static int send_success(int fd
,char *message
)
573 if(!(write_socket_len(fd
,protocol_string
[P_BEGIN
]) &&
574 write_socket_len(fd
,message
) &&
575 write_socket_len(fd
,protocol_string
[P_SUCCESS
]) &&
576 write_socket_len(fd
,protocol_string
[P_END
]))) return(0);
580 static int send_error(int fd
,char *message
,char *format_str
, ...)
582 char lines
[4],buffer
[PACKET_SIZE
+1];
587 va_start(ap
,format_str
);
588 vsprintf(buffer
,format_str
,ap
);
591 s1
=strrchr(message
,'\n');
592 s2
=strrchr(buffer
,'\n');
593 if(s1
!=NULL
) s1
[0]=0;
594 if(s2
!=NULL
) s2
[0]=0;
595 logprintf(LOG_ERR
,"error processing command: %s",message
);
596 logprintf(LOG_ERR
,"%s",buffer
);
597 if(s1
!=NULL
) s1
[0]='\n';
598 if(s2
!=NULL
) s2
[0]='\n';
602 for(i
=0;i
<len
;i
++) if(buffer
[i
]=='\n') n
++;
603 sprintf(lines
,"%d\n",n
);
605 if(!(write_socket_len(fd
,protocol_string
[P_BEGIN
]) &&
606 write_socket_len(fd
,message
) &&
607 write_socket_len(fd
,protocol_string
[P_ERROR
]) &&
608 write_socket_len(fd
,protocol_string
[P_DATA
]) &&
609 write_socket_len(fd
,lines
) &&
610 write_socket_len(fd
,buffer
) &&
611 write_socket_len(fd
,protocol_string
[P_END
]))) return(0);
615 static int get_command(int fd
)
618 char buffer
[PACKET_SIZE
+1],backup
[PACKET_SIZE
+1];
623 length
=read_timeout(fd
,buffer
,PACKET_SIZE
,0);
625 while(length
>packet_length
)
628 end
=strchr(buffer
,'\n');
631 logprintf(LOG_ERR
,"bad send packet: \"%s\"",buffer
);
632 /* remove clients that behave badly */
636 LOGPRINTF(1,"received command: \"%s\"",buffer
);
637 packet_length
=strlen(buffer
)+1;
639 strcpy(backup
,buffer
);strcat(backup
,"\n");
640 directive
=strtok(buffer
,WHITE_SPACE
);
643 if(!send_error(fd
,backup
,"bad send packet\n"))
647 for(i
=0;directives
[i
].name
!=NULL
;i
++)
649 if(strcasecmp(directive
,directives
[i
].name
)==0)
652 function(fd
,backup
,strtok(NULL
,"")))
658 if(!send_error(fd
,backup
,"unknown directive: \"%s\"\n",
662 if(length
>packet_length
)
666 memmove(buffer
,buffer
+packet_length
,
667 length
-packet_length
+1);
668 if(strchr(buffer
,'\n')==NULL
)
670 new_length
=read_timeout(fd
,buffer
+length
-
677 length
=length
-packet_length
+new_length
;
686 length
-=packet_length
;
692 if(length
==0) /* EOF: connection closed by client */
699 static void loop(int sockfd
, int lircdfd
)
711 logprintf(LOG_NOTICE
,"caught signal");
716 FD_SET(lircdfd
,&fds
);
717 maxfd
=max(sockfd
, lircdfd
);
721 FD_SET(clis
[i
].fd
,&fds
);
722 maxfd
=max(maxfd
,clis
[i
].fd
);
724 LOGPRINTF(3, "select");
725 ret
=select(maxfd
+1,&fds
,NULL
,NULL
,NULL
);
727 if(ret
==-1 && errno
!=EINTR
)
729 logprintf(LOG_ERR
,"select() failed");
730 logperror(LOG_ERR
,NULL
);
735 while(ret
==-1 && errno
==EINTR
);
739 if(FD_ISSET(clis
[i
].fd
,&fds
))
741 FD_CLR(clis
[i
].fd
,&fds
);
742 if(get_command(clis
[i
].fd
)==0)
748 logprintf(LOG_INFO
, "last client disconnected, shutting down");
754 if(FD_ISSET(sockfd
,&fds
))
756 LOGPRINTF(1,"registering local client");
759 if(FD_ISSET(lircdfd
,&fds
))
767 logprintf(LOG_ERR
, "connection lost");
774 static int schedule(int index
, char *config_string
)
776 struct event_info
*e
;
777 struct config_info
*c
, *n
;
778 LOGPRINTF(2, "schedule(%s): -%s-",
779 clis
[index
].ident_string
, config_string
);
781 e
= clis
[index
].first_event
;
782 while(e
->next
) e
= e
->next
;
785 while(c
&& c
->next
) c
= c
->next
;
787 n
= malloc(sizeof(*c
));
794 n
->config_string
= strdup(config_string
);
796 if(n
->config_string
== NULL
)
814 static int handle_input()
820 struct event_info
*e
, *n
;
823 LOGPRINTF(1,"input from lircd");
824 if(lirc_nextcode(&code
) != 0)
829 for(i
=0; i
<clin
; i
++)
831 n
= malloc(sizeof(*n
));
838 n
->code
= strdup(code
);
846 /* remove trailing \n */
847 n
->code
[strlen(n
->code
)-1] = 0;
852 e
= clis
[i
].first_event
;
853 while(e
&& e
->next
) e
= e
->next
;
857 clis
[i
].first_event
= n
;
864 LOGPRINTF(3, "input from lircd: \"%s\"", code
);
865 while((ret
=lirc_code2charprog(config
, code
, &config_string
, &prog
))==0 &&
870 LOGPRINTF(3, "%s: -%s-", prog
, config_string
);
871 for(i
=0; i
<clin
; i
++)
873 if(strcmp(prog
, clis
[i
].ident_string
) == 0)
875 if(!schedule(i
, config_string
))
882 for(i
=0; i
<clin
; i
++)
884 if(clis
[i
].pending_code
!= NULL
)
886 char message
[strlen(clis
[i
].pending_code
)+1];
889 LOGPRINTF(3, "pending_code(%s): -%s-",
890 clis
[i
].ident_string
, clis
[i
].pending_code
);
891 backup
= clis
[i
].pending_code
;
892 clis
[i
].pending_code
= NULL
;
894 sprintf(message
, "CODE %s\n", backup
);
895 (void) code_func(clis
[i
].fd
, message
, backup
);
904 int main(int argc
, char **argv
)
907 const char *socketfile
= NULL
;
908 mode_t permission
=S_IRUSR
|S_IWUSR
;
911 struct sigaction act
;
912 struct sockaddr_un addr
;
913 char dir
[FILENAME_MAX
+1] = { 0 };
919 static struct option long_options
[] =
921 {"help",no_argument
,NULL
,'h'},
922 {"version",no_argument
,NULL
,'v'},
923 {"permission",required_argument
,NULL
,'p'},
924 {"output",required_argument
,NULL
,'o'},
927 c
= getopt_long(argc
,argv
,"hvp:o:",long_options
,NULL
);
933 printf("Usage: %s [options] config-file\n",progname
);
934 printf("\t -h --help\t\t\tdisplay this message\n");
935 printf("\t -v --version\t\t\tdisplay version\n");
936 printf("\t -p --permission=mode\t\tfile permissions for socket\n");
937 printf("\t -o --output=socket\t\toutput socket filename\n");
938 return(EXIT_SUCCESS
);
940 printf("%s %s\n",progname
,VERSION
);
941 return(EXIT_SUCCESS
);
943 if(oatoi(optarg
)==-1)
945 fprintf(stderr
,"%s: invalid mode\n",progname
);
946 return(EXIT_FAILURE
);
948 permission
=oatoi(optarg
);
954 printf("Usage: %s [options] config-file\n",progname
);
955 return(EXIT_FAILURE
);
960 configfile
=argv
[optind
];
964 fprintf(stderr
,"%s: invalid argument count\n",progname
);
968 lircdfd
=lirc_init("lircrcd", 0);
974 /* read config file */
975 if(lirc_readconfig_only(configfile
,&config
,NULL
)!=0)
982 socket
=opensocket(configfile
, socketfile
, permission
, &addr
);
985 lirc_freeconfig(config
);
991 getcwd(dir
, sizeof(dir
));
994 fprintf(stderr
, "%s: daemon() failed\n", progname
);
998 lirc_freeconfig(config
);
1003 openlog(progname
, LOG_CONS
|LOG_PID
, LOG_USER
);
1005 signal(SIGPIPE
,SIG_IGN
);
1007 act
.sa_handler
=sigterm
;
1008 sigfillset(&act
.sa_mask
);
1009 act
.sa_flags
=SA_RESTART
; /* don't fiddle with EINTR */
1010 sigaction(SIGTERM
,&act
,NULL
);
1011 sigaction(SIGINT
,&act
,NULL
);
1012 sigaction(SIGHUP
,&act
,NULL
);
1014 logprintf(LOG_NOTICE
, "%s started", progname
);
1015 loop(socket
, lircdfd
);
1018 shutdown(socket
, 2);
1020 if(chdir(dir
) == 0) unlink(addr
.sun_path
);
1021 lirc_freeconfig(config
);
1023 return EXIT_SUCCESS
;