2 * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Eugene W. Stark.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $FreeBSD: src/libexec/xtend/xtend.c,v 1.9 1999/08/28 00:10:31 peter Exp $
32 * $DragonFly: src/libexec/xtend/xtend.c,v 1.3 2003/11/14 03:54:32 dillon Exp $
37 * Eugene W. Stark (stark@cs.sunysb.edu)
50 #include <sys/param.h>
52 #include <sys/types.h>
55 #include <sys/errno.h>
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
65 FILE *Log
; /* Log file */
66 FILE *User
; /* User connection */
67 STATUS Status
[16][16]; /* Device status table */
68 int status
; /* Status file descriptor */
69 int tw523
; /* tw523 controller */
70 int sock
; /* socket for user */
71 jmp_buf mainloop
; /* longjmp point after SIGHUP */
72 void onhup(); /* SIGHUP handler */
73 void onterm(); /* SIGTERM handler */
74 void onpipe(); /* SIGPIPE handler */
76 void checkpoint_status (void);
77 void initstatus (void);
78 void logpacket (unsigned char *);
79 void processpacket (unsigned char *);
80 int user_command (void);
87 char *twpath
= TWPATH
;
88 char *sockpath
= SOCKPATH
;
89 char logpath
[MAXPATHLEN
+1];
90 char statpath
[MAXPATHLEN
+1];
91 struct sockaddr_un sa
;
100 * Make sure we start out running as root
103 errx(1, "you must be root");
106 * Find out what UID/GID we are to run as
108 if((pw
= getpwnam(XTENUNAME
)) == NULL
)
109 errx(1, "no such user '%s'", XTENUNAME
);
110 if((gr
= getgrnam(XTENGNAME
)) == NULL
)
111 errx(1, "no such group '%s'", XTENGNAME
);
114 * Open the log file before doing anything else
116 strcpy(logpath
, X10DIR
);
117 if(stat(logpath
, &sb
) == -1 && errno
== ENOENT
) {
118 if(mkdir(logpath
, 0755) != -1) {
119 chown(logpath
, pw
->pw_uid
, gr
->gr_gid
);
121 errx(1, "can't create directory '%s'", logpath
);
124 strcat(logpath
, "/");
125 strcat(logpath
, X10LOGNAME
);
126 if((Log
= fopen(logpath
, "a")) == NULL
)
127 errx(1, "can't open log file '%s'", logpath
);
128 chown(logpath
, pw
->pw_uid
, gr
->gr_gid
);
133 if(daemon(0, 0) == -1) {
134 fprintf(Log
, "%s: Unable to become a daemon\n", thedate());
138 fprintf(Log
, "%s: %s [%d] started\n", thedate(), argv
[0], getpid());
141 * Get ahold of the TW523 device
143 if((tw523
= open(twpath
, O_RDWR
)) < 0) {
144 fprintf(Log
, "%s: Can't open %s\n", thedate(), twpath
);
148 fprintf(Log
, "%s: %s successfully opened\n", thedate(), twpath
);
151 * Put our pid in a file so we can be signalled by shell scripts
153 if((pidf
= fopen(PIDPATH
, "w")) == NULL
) {
154 fprintf(Log
, "%s: Error writing pid file: %s\n", thedate(), PIDPATH
);
158 fprintf(pidf
, "%d\n", getpid());
162 * Set up socket to accept user commands
164 if((sock
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
165 fprintf(Log
, "%s: Can't create socket\n", thedate());
169 strcpy(sa
.sun_path
, sockpath
);
170 sa
.sun_family
= AF_UNIX
;
172 if(bind(sock
, (struct sockaddr
*)(&sa
), strlen(sa
.sun_path
) + 2) < 0) {
173 fprintf(Log
, "%s: Can't bind socket to %s\n", thedate(), sockpath
);
177 if(listen(sock
, 5) < 0) {
178 fprintf(Log
, "%s: Can't listen on socket\n", thedate());
184 * Set proper ownership and permissions on the socket
186 if(chown(sockpath
, pw
->pw_uid
, gr
->gr_gid
) == -1 ||
187 chmod(sockpath
, 0660) == -1) {
188 fprintf(Log
, "%s: Can't set owner/permissions on socket\n", thedate());
194 * Give up root privileges
200 * Initialize the status table
202 strcpy(statpath
, X10DIR
);
203 strcat(statpath
, "/");
204 strcat(statpath
, X10STATNAME
);
205 if((status
= open(statpath
, O_RDWR
)) < 0) {
206 if((status
= open(statpath
, O_RDWR
| O_CREAT
, 0666)) < 0) {
207 fprintf(Log
, "%s: Can't open %s\n", thedate(), statpath
);
211 if(write(status
, Status
, 16 * 16 * sizeof(STATUS
))
212 != 16 * 16 * sizeof(STATUS
)) {
213 fprintf(Log
, "%s: Error initializing status file\n", thedate());
221 * Return here on SIGHUP after closing and reopening log file.
222 * Also on SIGPIPE after closing user connection.
224 signal(SIGTERM
, onterm
);
225 signal(SIGHUP
, onhup
);
226 signal(SIGPIPE
, onpipe
);
230 * Now start the main processing loop.
236 unsigned char rpkt
[3];
242 if(User
!= NULL
) FD_SET(user
, &fs
);
243 else FD_SET(sock
, &fs
);
244 sel
= select(FD_SETSIZE
, &fs
, 0, 0, &tv
);
247 * Cancel brightening and dimming on ALL units on ALL house codes,
248 * because the fact that we haven't gotten a packet for awhile means
249 * that there was a gap in transmission.
251 for(h
= 0; h
< 16; h
++) {
252 for(k
= 0; k
< 16; k
++) {
254 if(s
->selected
== BRIGHTENING
|| s
->selected
== DIMMING
) {
256 s
->lastchange
= time(NULL
);
264 * Now that we've done this stuff, we'll set the timeout a little
265 * longer, so we don't keep looping too frequently.
272 * While there is stuff happening, we keep a short timeout, so we
273 * don't get stuck for some unknown reason, and so we can keep the
274 * brightening and dimming data up-to-date.
278 if(FD_ISSET(tw523
, &fs
)) { /* X10 data arriving from TW523 */
279 if(read(tw523
, rpkt
, 3) < 3) {
280 fprintf(Log
, "%s: Error reading from TW523\n", thedate());
285 } else if(FD_ISSET(user
, &fs
) && User
!= NULL
) {
287 fprintf(Log
, "%s: Closing user connection\n", thedate());
291 } else if(FD_ISSET(sock
, &fs
)) { /* Accept a connection */
293 int len
= sizeof(struct sockaddr_un
);
294 if((user
= accept(sock
, (struct sockaddr
*)(&sa
), &len
)) >= 0) {
295 fprintf(Log
, "%s: Accepting user connection\n", thedate());
296 if((User
= fdopen(user
, "w+")) == NULL
) {
297 fprintf(Log
, "%s: Can't attach socket to stream\n", thedate());
300 fprintf(Log
, "%s: Failure in attempt to accept connection\n", thedate());
316 cp
= cp1
= ctime(&tod
);
317 while(*cp1
!= '\n') cp1
++;
323 * When SIGHUP received, close and reopen the Log file
328 char logpath
[MAXPATHLEN
+1];
330 fprintf(Log
, "%s: SIGHUP received, reopening Log\n", thedate());
332 strcpy(logpath
, X10DIR
);
333 strcat(logpath
, "/");
334 strcat(logpath
, X10LOGNAME
);
335 if((Log
= fopen(logpath
, "a")) == NULL
)
336 errx(1, "can't open log file '%s'", logpath
);
337 longjmp(mainloop
, 1);
342 * When SIGTERM received, just exit normally
347 fprintf(Log
, "%s: SIGTERM received, shutting down\n", thedate());
353 * When SIGPIPE received, reset user connection
358 fprintf(Log
, "%s: SIGPIPE received, resetting user connection\n",
364 longjmp(mainloop
, 1);