File:  [DragonFly] / src / libexec / xtend / xtend.c
Revision 1.3: download - view: text, annotated - select for diffs
Fri Nov 14 03:54:32 2003 UTC (10 years, 10 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_2_0_Slip, DragonFly_RELEASE_2_0, DragonFly_RELEASE_1_8_Slip, DragonFly_RELEASE_1_8, DragonFly_RELEASE_1_6_Slip, DragonFly_RELEASE_1_6, DragonFly_RELEASE_1_4_Slip, DragonFly_RELEASE_1_4, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_RELEASE_1_12_Slip, DragonFly_RELEASE_1_12, DragonFly_RELEASE_1_10_Slip, DragonFly_RELEASE_1_10, DragonFly_Preview, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
__P removal.

Submitted-by: Craig Dooley <craig@xlnx-x.net>

    1: /*-
    2:  * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    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.
   18:  *
   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
   29:  * SUCH DAMAGE.
   30:  *
   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 $
   33:  */
   34: 
   35: /*
   36:  * xtend - X-10 daemon
   37:  * Eugene W. Stark (stark@cs.sunysb.edu)
   38:  * January 14, 1993
   39:  */
   40: 
   41: #include <err.h>
   42: #include <pwd.h>
   43: #include <setjmp.h>
   44: #include <signal.h>
   45: #include <stdio.h>
   46: #include <stdlib.h>
   47: #include <string.h>
   48: #include <time.h>
   49: #include <unistd.h>
   50: #include <sys/param.h>
   51: #include <sys/file.h>
   52: #include <sys/types.h>
   53: #include <sys/time.h>
   54: #include <sys/stat.h>
   55: #include <sys/errno.h>
   56: #include <sys/ioctl.h>
   57: #include <sys/socket.h>
   58: #include <sys/un.h>
   59: #include <grp.h>
   60: 
   61: #include "xtend.h"
   62: #include "xten.h"
   63: #include "paths.h"
   64: 
   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 */
   75: 
   76: void checkpoint_status (void);
   77: void initstatus (void);
   78: void logpacket (unsigned char *);
   79: void processpacket (unsigned char *);
   80: int user_command (void);
   81: 
   82: int
   83: main(argc, argv)
   84: int argc;
   85: char *argv[];
   86: {
   87:   char *twpath = TWPATH;
   88:   char *sockpath = SOCKPATH;
   89:   char logpath[MAXPATHLEN+1];
   90:   char statpath[MAXPATHLEN+1];
   91:   struct sockaddr_un sa;
   92:   struct timeval tv;
   93:   struct passwd *pw;
   94:   struct group *gr;
   95:   struct stat sb;
   96:   int user;
   97:   FILE *pidf;
   98: 
   99:   /*
  100:    * Make sure we start out running as root
  101:    */
  102:   if(geteuid() != 0)
  103:     errx(1, "you must be root");
  104: 
  105:   /*
  106:    * Find out what UID/GID we are to run as
  107:    */
  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);
  112: 
  113:   /*
  114:    * Open the log file before doing anything else
  115:    */
  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);
  120:     } else {
  121:       errx(1, "can't create directory '%s'", logpath);
  122:     }
  123:   }
  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);
  129: 
  130:   /*
  131:    * Become a daemon
  132:    */
  133:   if(daemon(0, 0) == -1) {
  134:     fprintf(Log, "%s:  Unable to become a daemon\n", thedate());
  135:     fclose(Log);
  136:     exit(1);
  137:   }
  138:   fprintf(Log, "%s:  %s [%d] started\n", thedate(), argv[0], getpid());
  139: 
  140:   /*
  141:    * Get ahold of the TW523 device
  142:    */
  143:   if((tw523 = open(twpath, O_RDWR)) < 0) {
  144:     fprintf(Log, "%s:  Can't open %s\n", thedate(), twpath);
  145:     fclose(Log);
  146:     exit(1);
  147:   }
  148:   fprintf(Log, "%s:  %s successfully opened\n", thedate(), twpath);
  149: 
  150:   /*
  151:    * Put our pid in a file so we can be signalled by shell scripts
  152:    */
  153:   if((pidf = fopen(PIDPATH, "w")) == NULL) {
  154:       fprintf(Log, "%s:  Error writing pid file: %s\n", thedate(), PIDPATH);
  155:       fclose(Log);
  156:       exit(1);
  157:   }
  158:   fprintf(pidf, "%d\n", getpid());
  159:   fclose(pidf);
  160: 
  161:   /*
  162:    * Set up socket to accept user commands
  163:    */
  164:   if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  165:     fprintf(Log, "%s:  Can't create socket\n", thedate());
  166:     fclose(Log);
  167:     exit(1);
  168:   }
  169:   strcpy(sa.sun_path, sockpath);
  170:   sa.sun_family = AF_UNIX;
  171:   unlink(sockpath);
  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);
  174:     fclose(Log);
  175:     exit(1);
  176:   }
  177:   if(listen(sock, 5) < 0) {
  178:     fprintf(Log, "%s:  Can't listen on socket\n", thedate());
  179:     fclose(Log);
  180:     exit(1);
  181:   }
  182: 
  183:   /*
  184:    * Set proper ownership and permissions on the socket
  185:    */
  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());
  189:     fclose(Log);
  190:     exit(1);
  191:   }
  192: 
  193:   /*
  194:    * Give up root privileges
  195:    */
  196:   setgid(pw->pw_gid);
  197:   setuid(pw->pw_uid);
  198: 
  199:   /*
  200:    * Initialize the status table
  201:    */
  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);
  208:       fclose(Log);
  209:       exit(1);
  210:     }
  211:     if(write(status, Status, 16 * 16 * sizeof(STATUS))
  212:        != 16 * 16 * sizeof(STATUS)) {
  213:       fprintf(Log, "%s:  Error initializing status file\n", thedate());
  214:       fclose(Log);
  215:       exit(1);
  216:     }
  217:   }
  218:   initstatus();
  219: 
  220:   /*
  221:    * Return here on SIGHUP after closing and reopening log file.
  222:    * Also on SIGPIPE after closing user connection.
  223:    */
  224:   signal(SIGTERM, onterm);
  225:   signal(SIGHUP, onhup);
  226:   signal(SIGPIPE, onpipe);
  227:   setjmp(mainloop);
  228: 
  229:   /*
  230:    * Now start the main processing loop.
  231:    */
  232:   tv.tv_sec = 0;
  233:   tv.tv_usec = 250000;
  234:   while(1) {
  235:     fd_set fs;
  236:     unsigned char rpkt[3];
  237:     int sel, h, k;
  238:     STATUS *s;
  239: 
  240:     FD_ZERO(&fs);
  241:     FD_SET(tw523, &fs);
  242:     if(User != NULL) FD_SET(user, &fs);
  243:     else FD_SET(sock, &fs);
  244:     sel = select(FD_SETSIZE, &fs, 0, 0, &tv);
  245:     if(sel == 0) {
  246:       /*
  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.
  250:        */
  251:       for(h = 0; h < 16; h++) {
  252: 	for(k = 0; k < 16; k++) {
  253: 	  s = &Status[h][k];
  254: 	  if(s->selected == BRIGHTENING || s->selected == DIMMING) {
  255: 	    s->selected = IDLE;
  256: 	    s->lastchange = time(NULL);
  257: 	    s->changed = 1;
  258: 	  }
  259: 	}
  260:       }
  261:       fflush(Log);
  262:       checkpoint_status();
  263:       /*
  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.
  266:        */
  267:       tv.tv_sec = 60;
  268:       tv.tv_usec = 0;
  269:       continue;
  270:     }
  271:     /*
  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.
  275:      */
  276:     tv.tv_sec = 0;
  277:     tv.tv_usec = 250000;
  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());
  281:       } else {
  282: 	logpacket(rpkt);
  283: 	processpacket(rpkt);
  284:       }
  285:     } else if(FD_ISSET(user, &fs) && User != NULL) {
  286:       if(user_command()) {
  287: 	fprintf(Log, "%s:  Closing user connection\n", thedate());
  288: 	fclose(User);
  289: 	User = NULL;
  290:       }
  291:     } else if(FD_ISSET(sock, &fs)) {  /* Accept a connection */
  292:       if (User == NULL) {
  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());
  298: 	  }
  299: 	} else {
  300: 	  fprintf(Log, "%s:  Failure in attempt to accept connection\n", thedate());
  301: 	}
  302:       } else {
  303: 	/* "Can't happen */
  304:       }
  305:     }
  306:   }
  307:   /* Not reached */
  308: }
  309: 
  310: char *thedate()
  311: {
  312:   char *cp, *cp1;
  313:   time_t tod;
  314: 
  315:   tod = time(NULL);
  316:   cp = cp1 = ctime(&tod);
  317:   while(*cp1 != '\n') cp1++;
  318:   *cp1 = '\0';
  319:   return(cp);
  320: }
  321: 
  322: /*
  323:  * When SIGHUP received, close and reopen the Log file
  324:  */
  325: 
  326: void onhup()
  327: {
  328:   char logpath[MAXPATHLEN+1];
  329: 
  330:   fprintf(Log, "%s:  SIGHUP received, reopening Log\n", thedate());
  331:   fclose(Log);
  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);
  338:   /* No return */
  339: }
  340: 
  341: /*
  342:  * When SIGTERM received, just exit normally
  343:  */
  344: 
  345: void onterm()
  346: {
  347:   fprintf(Log, "%s:  SIGTERM received, shutting down\n", thedate());
  348:   fclose(Log);
  349:   exit(0);
  350: }
  351: 
  352: /*
  353:  * When SIGPIPE received, reset user connection
  354:  */
  355: 
  356: void onpipe()
  357: {
  358:   fprintf(Log, "%s:  SIGPIPE received, resetting user connection\n",
  359: 	  thedate());
  360:   if(User != NULL) {
  361:     fclose(User);
  362:     User = NULL;
  363:   }
  364:   longjmp(mainloop, 1);
  365:   /* No return */
  366: }