to github
[svn42.git] / powersensordaemon / powersensordaemon.c
index 99dbf74..133533e 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "daemon.h"
 
+#include "autosample.h"
+
 int init_command_socket(const char* path)
 {
   int fd = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -74,19 +76,50 @@ int init_command_socket(const char* path)
   return fd;
 }
 
+void clear_fd(int fd)
+{
+  fd_set fds;
+  struct timeval tv;
+  FD_ZERO(&fds);
+  FD_SET(fd, &fds);
+  tv.tv_sec = 0;
+  tv.tv_usec = 50000;
+  for(;;) {
+    int ret = select(fd+1, &fds, NULL, NULL, &tv);
+    if(ret > 0) {
+      char buffer[100];
+      ret = read(fd, buffer, sizeof(buffer));
+    }
+    else
+      break;
+  }
+}
+
 int send_command(int tty_fd, cmd_t* cmd)
 {
   if(!cmd)
     return -1;
   
-  char c;
+  if(!cmd->param)
+    return 0;
+
+  unsigned int j,cmd_param_len = strnlen(cmd->param,60);
+  char c[cmd_param_len];
   switch(cmd->cmd) {
-  case POWER: {
-    c = 'A'; // get command from powerids[cmd->param]
+  case POWER_ON: {
+    for (j=0; j< cmd_param_len; j++)
+      c[j] = toupper(cmd->param[j]);
+    break;
+  }
+  case POWER_OFF: {
+    for (j=0; j< cmd_param_len; j++)
+      c[j] = tolower(cmd->param[j]);
     break;
   }
   case SAMPLE: {
-    c = 'T'; // get command from sampledevs[cmd->param]
+    for (j=0; j< cmd_param_len; j++)
+      c[j] = cmd->param[j];
     break;
   }
   default: return 0;
@@ -94,7 +127,7 @@ int send_command(int tty_fd, cmd_t* cmd)
   
   int ret;
   do {
-    ret = write(tty_fd, &c, 1);
+    ret = write(tty_fd, c, cmd_param_len);
   } while(!ret || (ret == -1 && errno == EINTR));
 
   if(ret > 0) {
@@ -147,7 +180,7 @@ int send_response(int fd, const char* response)
       log_printf(DEBUG, "sent %s to %d additional listeners", TYPE_NAME,listener_cnt);
   
 
-int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
+int process_cmd(char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst, options_t* opt)
 {
   log_printf(DEBUG, "processing command from %d", fd);
 
@@ -155,8 +188,14 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
     return -1;
   
   cmd_id_t cmd_id;
-  if(!strncmp(cmd, "power", 5))
-    cmd_id = POWER;
+  if(!strncmp(cmd, "power on", 8)) {
+    cmd_id = POWER_ON;
+    cmd[5] = '_';
+  }
+  else if(!strncmp(cmd, "power off", 9)) {
+    cmd_id = POWER_OFF;
+    cmd[5] = '_';
+  }
   else if(!strncmp(cmd, "sample", 6))
     cmd_id = SAMPLE;
   else if(!strncmp(cmd, "log", 3))
@@ -169,10 +208,28 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
     return 0;
   }
   char* param = strchr(cmd, ' ');
-  if(param) 
+  if(param)
     param++;
 
-  if(cmd_id == POWER || cmd_id == SAMPLE) {
+  if(cmd_id == POWER_ON || cmd_id == POWER_OFF) {
+    char* orig_param = param;
+    param = key_value_storage_find(&(opt->powerids_), param);
+    if(!param) {
+      send_response(fd, "Error: invalid power id");
+      log_printf(WARNING, "invalid power id '%s' in command from %d", orig_param, fd);
+    }
+  }
+
+  if(cmd_id == SAMPLE) {
+    char* orig_param = param;
+    param = key_value_storage_find(&(opt->sampledevs_), param);
+    if(!param) {
+      send_response(fd, "Error: invalid sample device");
+      log_printf(WARNING, "invalid sample device '%s' in command from %d", orig_param, fd);
+    }
+  }
+
+  if(cmd_id == POWER_ON || cmd_id == POWER_OFF || cmd_id == SAMPLE) {
     char* resp;
     asprintf(&resp, "Request: %s", cmd);
     if(resp) {
@@ -185,7 +242,8 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
   }
 
   switch(cmd_id) {
-  case POWER:
+  case POWER_ON:
+  case POWER_OFF:
   case SAMPLE: {
     int ret = cmd_push(cmd_q, fd, cmd_id, param);
     if(ret)
@@ -207,16 +265,14 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
       if(!param || !strncmp(param, "all", 3)) {
         listener->request_listener = 1;
         listener->error_listener = 1;
-        listener->temp_listener = 1;
-        listener->photo_listener = 1;
+        listener->sensor_listener = 1;
         listener->movement_listener = 1;
         listener->button_listener = 1;
       }
       else if(!strncmp(param, "none", 4)) {
         listener->request_listener = 0;
         listener->error_listener = 0;
-        listener->temp_listener = 0;
-        listener->photo_listener = 0;
+        listener->sensor_listener = 0;
         listener->movement_listener = 0;
         listener->button_listener = 0;
       }
@@ -224,10 +280,8 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
         listener->request_listener = 1;
       else if(!strncmp(param, "error", 5))
         listener->error_listener = 1;
-      else if(!strncmp(param, "temp", 4))
-        listener->temp_listener = 1;      
-      else if(!strncmp(param, "photo", 5))
-        listener->photo_listener = 1;      
+      else if(!strncmp(param, "sensor", 6))
+        listener->sensor_listener = 1;      
       else if(!strncmp(param, "movement", 8))
         listener->movement_listener = 1;      
       else if(!strncmp(param, "button", 6))
@@ -248,21 +302,21 @@ int process_cmd(const char* cmd, int fd, cmd_t **cmd_q, client_t* client_lst)
   return 0;
 }
 
-int nonblock_recvline(read_buffer_t* buffer, int fd, cmd_t** cmd_q, client_t* client_lst)
+int nonblock_readline(read_buffer_t* buffer, int fd, cmd_t** cmd_q, client_t* client_lst, options_t* opt)
 {
   int ret = 0;
   for(;;) {
-    ret = recv(fd, &buffer->buf[buffer->offset], 1, 0);
-    if(!ret)
+    ret = read(fd, &buffer->buf[buffer->offset], 1);
+    if(!ret || (ret == -1 && errno == EBADF))
       return 2;
-    if(ret == -1 && errno == EAGAIN)
+    if(ret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
       return 0;
     else if(ret < 0)
       break;
 
     if(buffer->buf[buffer->offset] == '\n') {
       buffer->buf[buffer->offset] = 0;
-      ret = process_cmd(buffer->buf, fd, cmd_q, client_lst);
+      ret = process_cmd(buffer->buf, fd, cmd_q, client_lst, opt);
       buffer->offset = 0;
       break;
     }
@@ -278,8 +332,9 @@ int nonblock_recvline(read_buffer_t* buffer, int fd, cmd_t** cmd_q, client_t* cl
   return ret;
 }
 
-int process_tty(read_buffer_t* buffer, int tty_fd, cmd_t **cmd_q, client_t* client_lst)
+int process_tty(read_buffer_t* buffer, int tty_fd, cmd_t **cmd_q, client_t* client_lst, options_t* opt)
 {
+  u_int8_t *response_data;
   int ret = 0;
   struct timeval tv;
   fd_set fds;
@@ -311,28 +366,54 @@ int process_tty(read_buffer_t* buffer, int tty_fd, cmd_t **cmd_q, client_t* clie
 
       log_printf(NOTICE, "firmware: %s", buffer->buf);      
 
+      /* modify response if necessary */
+      response_data = buffer->buf;
+      if(!strncmp(buffer->buf, "Sensor ", 7)) {
+        if (buffer->buf[7] != 0)
+        {
+          char *sampledev_key;
+          if (asprintf(&sampledev_key, "%c",buffer->buf[7]))
+          {
+            char const *sampledev_name = key_value_storage_find_first_stringvalue(&(opt->sampledevs_), sampledev_key);
+            if(sampledev_name)
+            {
+              char *rev_lookuped_output;
+              if (asprintf(&rev_lookuped_output, "%s%s", sampledev_name, &(buffer->buf[8]) ))
+                response_data = rev_lookuped_output;
+            }
+            else
+              log_printf(WARNING, "unknown sample device key '%s' encountered", sampledev_key);
+            free(sampledev_key);
+          }
+        }
+      }
+
       int cmd_fd = -1;
       if(cmd_q && (*cmd_q)) {
         cmd_fd = (*cmd_q)->fd;
-        send_response(cmd_fd, buffer->buf);
+        send_response(cmd_fd, response_data);
       }
       
       if(!strncmp(buffer->buf, "Error:", 6)) {
-        SEND_TO_LISTENER(error_listener, "error", cmd_fd, buffer->buf);
+        SEND_TO_LISTENER(error_listener, "error", cmd_fd, response_data);
       }
       
       if(!strncmp(buffer->buf, "movement", 8)) {
-        SEND_TO_LISTENER(movement_listener, "movement", cmd_fd, buffer->buf);
+        SEND_TO_LISTENER(movement_listener, "movement", cmd_fd, response_data);
       }
 
       if(!strncmp(buffer->buf, "PanicButton", 11)) {
-        SEND_TO_LISTENER(button_listener, "panic buttont", cmd_fd, buffer->buf);
+        SEND_TO_LISTENER(button_listener, "panic button", cmd_fd, response_data);
       }
 
-      if(!strncmp(buffer->buf, "Temp ", 5)) {
-        SEND_TO_LISTENER(temp_listener, "", cmd_fd, buffer->buf);
+      if(!strncmp(buffer->buf, "Sensor ", 7)) {
+        SEND_TO_LISTENER(sensor_listener, "sensor data", cmd_fd, response_data);
       }
 
+      /* free allocated buffer if response was modified */
+      if (response_data != buffer->buf)
+        free(response_data);
+
       cmd_pop(cmd_q);
       buffer->offset = 0;
       return 0;
@@ -349,20 +430,31 @@ int process_tty(read_buffer_t* buffer, int tty_fd, cmd_t **cmd_q, client_t* clie
   return ret;
 }
 
-int main_loop(int tty_fd, int cmd_listen_fd)
+int main_loop(int tty_fd, int cmd_listen_fd, autosample_process_t* autosample, options_t* opt)
 {
   log_printf(NOTICE, "entering main loop");
 
   fd_set readfds, tmpfds;
   FD_ZERO(&readfds);
+
+  clear_fd(tty_fd);
   FD_SET(tty_fd, &readfds);
   FD_SET(cmd_listen_fd, &readfds);
   int max_fd = tty_fd > cmd_listen_fd ? tty_fd : cmd_listen_fd;
+
+  u_int8_t autosample_enabled = 0;
+  if(autosample->pid_ > 0) {
+    clear_fd(autosample->write_fd_);
+    FD_SET(autosample->write_fd_, &readfds);
+    max_fd = (max_fd < autosample->write_fd_) ? autosample->write_fd_ : max_fd;
+  }
   cmd_t* cmd_q = NULL;
   client_t* client_lst = NULL;
 
   read_buffer_t tty_buffer;
   tty_buffer.offset = 0;
+  read_buffer_t autosample_buffer;
+  autosample_buffer.offset = 0;
 
   int sig_fd = signal_init();
   if(sig_fd < 0)
@@ -402,7 +494,7 @@ int main_loop(int tty_fd, int cmd_listen_fd)
     }
    
     if(FD_ISSET(tty_fd, &tmpfds)) {
-      return_value = process_tty(&tty_buffer, tty_fd, &cmd_q, client_lst);
+      return_value = process_tty(&tty_buffer, tty_fd, &cmd_q, client_lst, opt);
       if(return_value)
         break;
     }
@@ -421,10 +513,22 @@ int main_loop(int tty_fd, int cmd_listen_fd)
       client_add(&client_lst, new_fd);
     }
 
+    if(autosample->pid_ > 0 && FD_ISSET(autosample->write_fd_, &tmpfds)) {
+      return_value = nonblock_readline(&autosample_buffer, autosample->write_fd_, &cmd_q, client_lst, opt);
+      if(return_value == 2) {
+        log_printf(WARNING, "autosample not running, removing pipe to it");
+        FD_CLR(autosample->write_fd_, &readfds);
+        return_value = 0;
+        continue;
+      }
+      if(return_value)
+        break;
+    }
+
     client_t* lst = client_lst;
     while(lst) {
       if(FD_ISSET(lst->fd, &tmpfds)) {
-        return_value = nonblock_recvline(&(lst->buffer), lst->fd, &cmd_q, client_lst);
+        return_value = nonblock_readline(&(lst->buffer), lst->fd, &cmd_q, client_lst, opt);
         if(return_value == 2) {
           log_printf(DEBUG, "removing closed command connection (fd=%d)", lst->fd);
           client_t* deletee = lst;
@@ -438,11 +542,31 @@ int main_loop(int tty_fd, int cmd_listen_fd)
           break;
 
       }
-      lst = lst->next;
+      if(lst)
+        lst = lst->next;
     }
 
     if(cmd_q && !cmd_q->sent)
       send_command(tty_fd, cmd_q);
+
+    if(autosample->pid_ > 0) {
+      lst = client_lst;
+      int listener_cnt = 0;
+      while(lst) {
+        if(lst->sensor_listener)
+          listener_cnt++;
+        lst = lst->next;
+      }
+      if((!autosample_enabled && listener_cnt > 0) ||
+         (autosample_enabled && listener_cnt == 0)) {
+        if(autosample_enabled) autosample_enabled = 0;
+        else autosample_enabled = 1;
+        int ret;
+        do {
+          ret = write(autosample->read_fd_, &autosample_enabled, 1);
+        } while(!ret || (ret == -1 && errno == EINTR));
+      }
+    }
   }
 
   cmd_clear(&cmd_q);
@@ -487,21 +611,7 @@ int setup_tty(int fd)
     return ret;
   }
 
-  fd_set fds;
-  struct timeval tv;
-  FD_ZERO(&fds);
-  FD_SET(fd, &fds);
-  tv.tv_sec = 0;
-  tv.tv_usec = 50000;
-  for(;;) {
-    ret = select(fd+1, &fds, NULL, NULL, &tv);
-    if(ret > 0) {
-      char buffer[100];
-      ret = read(fd, buffer, sizeof(buffer));
-    }
-    else
-      break;
-  }
+  clear_fd(fd);
 
   return 0;
 }
@@ -550,7 +660,11 @@ int main(int argc, char* argv[])
     }
   }
   log_printf(NOTICE, "just started...");
-  options_parse_post(&opt);
+  if(options_parse_post(&opt)) {
+    options_clear(&opt);
+    log_close();
+    exit(-1);
+  }
 
   priv_info_t priv;
   if(opt.username_)
@@ -592,6 +706,20 @@ int main(int argc, char* argv[])
     fprintf(pid_file, "%d", pid);
     fclose(pid_file);
   }
+  
+  autosample_process_t autosample;
+  autosample.pid_ = -1;
+  autosample.write_fd_ = -1;
+  autosample.read_fd_ = -1;
+  if(key_value_storage_length(&opt.autosampledevs_) > 0) {
+    log_printf(NOTICE, "starting autosample process");
+    int ret = start_autosample_process(&opt, &autosample);
+    if(ret == -1) {
+      options_clear(&opt);
+      log_close();
+      exit(1);
+    }
+  }
 
   int cmd_listen_fd = init_command_socket(opt.command_sock_);
   if(cmd_listen_fd < 0) {
@@ -610,7 +738,7 @@ int main(int argc, char* argv[])
       if(ret)
         ret = 2;
       else
-        ret = main_loop(tty_fd, cmd_listen_fd);
+        ret = main_loop(tty_fd, cmd_listen_fd, &autosample, &opt);
     }
 
     if(ret == 2) {
@@ -626,6 +754,8 @@ int main(int argc, char* argv[])
   close(cmd_listen_fd);
   if(tty_fd > 0)
     close(tty_fd);
+  if(autosample.pid_ > 0)
+    kill(autosample.pid_, SIGTERM);
 
   if(!ret)
     log_printf(NOTICE, "normal shutdown");