Exemple #1
0
int main(int argc, char **argv)
{
  struct set *ss;
  struct remote *rx;
  struct katcl_parse *px;
  struct katcl_line *k;
  struct timeval delta, start, stop;
  fd_set fsr, fsw;

  char *app, *parm, *cmd, *copy, *ptr, *servers, *extra, *label;
  int i, j, c, fd, mfd, count;
  int verbose, result, status, info, timeout, flags, show, munge, once;
  int xmit, code;
  unsigned int len;
  
  servers = getenv("KATCP_SERVER");
  if(servers == NULL){
    servers = "localhost:7147";
  }
  
  once = 1;
  munge = 0;
  info = 1;
  verbose = 1;
  i = j = 1;
  app = argv[0];
  timeout = 0;
  k = NULL;
  show = 1;
  parm = NULL;
  extra = NULL;
  label = KCPPAR_NAME;
  count = 0;
  px = NULL;

  k = create_katcl(STDOUT_FILENO);
  if(k == NULL){
    fprintf(stderr, "%s: unable to create katcp message logic\n", app);
    return 4;
  }

  ss = create_set();
  if(ss == NULL){
    sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to set up command set data structures");
    return 4;
  }

  xmit = (-1);

  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {

        case 'h' :
          usage(app);
          return 0;
        case 'i' : 
          info = 1 - info;
          j++;
          break;

        case 'm' : 
          munge = 1;
          j++;
          break;

        case 'n' : 
          show = 0;
          j++;
          break;


        case 'q' : 
          verbose = 0;
          j++;
          break;

        case 'x' : 
          xmit = 0;
          j++;
          break;

        case 'l' :
        case 's' :
        case 't' :

          j++;
          if (argv[i][j] == '\0') {
            j = 0;
            i++;
          }
          if (i >= argc) {
            sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "argument needs a parameter");
            return 2;
          }

          switch(c){
            case 'l' :
              label = argv[i] + j;
              break;
            case 's' :
              servers = argv[i] + j;
              break;
            case 't' :
              timeout = atoi(argv[i] + j);
              break;
          }

          i++;
          j = 1;
          break;

        case 'v' : 
          verbose++;
          j++;
          break;

        case '-' :
          j++;
          break;
        case '\0':
          j = 1;
          i++;
          break;
        default:
          sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unknown option -%c", argv[i][j]);
          return 2;
      }
    } else {

      copy = NULL;

      if(xmit < 0){
        /* WARNING: this could make error detection worse */
        xmit = 0;
      }

      if(xmit == 0){
        px = create_referenced_parse_katcl();
        if(px == NULL){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to create parse instance for <%s ...>", argv[i]);
          return 4;
        }

        switch(argv[i][0]){
          case KATCP_REQUEST : 
          case KATCP_REPLY   :
          case KATCP_INFORM  :
            ptr = argv[i];
            break;
          default :
            copy = malloc(strlen(argv[i]) + 1);
            if(copy == NULL){
              sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to allocate temporary storage for %s", argv[i]);
              return 4;
            }
            copy[0] = KATCP_REQUEST;
            strcpy(copy + 1, argv[i]);
            ptr = copy;
            break;
        }
        flags = KATCP_FLAG_FIRST;
      } else {
        ptr = argv[i];
        flags = 0;
      }

      i++;
      j = 1;
      if((i >= argc) || (argv[i][0] == '-')){
        flags |= KATCP_FLAG_LAST;
      }

      if(add_string_parse_katcl(px, flags, ptr) < 0){
        sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to add parameter %s", ptr);
        return 4;
      }

      if(flags & KATCP_FLAG_LAST){
#ifdef DEBUG
        fprintf(stderr, "par: loading command for servers %s\n", servers);
#endif
        if(load_parse_set(ss, servers, px) < 0){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to load command into server set %s", servers);
          return 4;
        }
        destroy_parse_katcl(px);
        px = NULL;
      }

      if(copy){
        free(copy);
        copy = NULL;
      }

      xmit++;
    }
  }

  if(timeout == 0){
    timeout = 5000 * ss->s_count;
  }

  gettimeofday(&start, NULL);

  delta.tv_sec = timeout / 1000;
  delta.tv_usec = (timeout % 1000) * 1000;

  add_time_katcp(&stop, &start, &delta);

  if(activate_remotes(ss, k) < 0){
    sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to initiate connections to remote servers");
    return 3;
  }

  for(ss->s_finished = 0; ss->s_finished < ss->s_count;){

    mfd = 0;
    FD_ZERO(&fsr);
    FD_ZERO(&fsw);

    if(k){
      if(flushing_katcl(k)){
        mfd = fileno_katcl(k);
        FD_SET(mfd, &fsw);
      }
    }

    for(i = 0; i < ss->s_count; i++){
      rx = ss->s_vector[i];
      if(rx->r_line){
        fd = fileno_katcl(rx->r_line);
        if(fd > mfd){
          mfd = fd;
        }
      } else {
        fd = (-1); /* WARNING: live dangerously */
      }

      switch(rx->r_state){
        case RX_SETUP :
          FD_SET(fd, &fsw);
          break;
        case RX_UP :
          if(flushing_katcl(rx->r_line)){ /* only write data if we have some */
            FD_SET(fd, &fsw);
          }
          FD_SET(fd, &fsr);
          break;
          /* case RX_OK : */
          /* case RX_FAIL : */
          /* case RX_BAD  : */
        default :
          break;
      }
    }

    gettimeofday(&start, NULL);
    sub_time_katcp(&delta, &stop, &start);

    result = select(mfd + 1, &fsr, &fsw, NULL, &delta);
    switch(result){
      case -1 :
        switch(errno){
          case EAGAIN :
          case EINTR  :
            continue; /* WARNING */
          default  :
            sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "select failed: %s", strerror(errno));
            return 4;
        }
        break;
      case  0 :
        sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "requests timed out after %dms", timeout);
        /* could terminate cleanly here, but ... */
        return 3;
    }

    if(k){
      fd = fileno_katcl(k);
      if(FD_ISSET(fd, &fsw)){
        write_katcl(k); /* WARNING: ignores write failures - unable to do much about it */
      }
    }

    for(i = 0; i < ss->s_count; i++){
      rx = ss->s_vector[i];
      if(rx->r_line){
        fd = fileno_katcl(rx->r_line);
      } else {
        fd = (-1); /* WARNING: live dangerously, will cause select to core dump if logic is incorrect */
      }

      switch(rx->r_state){
        case RX_SETUP :
          if(FD_ISSET(fd, &fsw)){
            len = sizeof(int);
            result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &code, &len);
            if(result == 0){
              switch(code){
                case 0 :
                  if(verbose){
                    log_message_katcl(k, KATCP_LEVEL_DEBUG, label, "async connect to %s succeeded", rx->r_name);
                  }
                  if(next_request(rx) < 0){
                    log_message_katcl(k, KATCP_LEVEL_ERROR, label, "failed to load request for destination %s", rx->r_name);
                    update_state(ss, rx, RX_BAD);
                  } else {
                    update_state(ss, rx, RX_UP);
                  }
                  break;
                case EINPROGRESS :
                  log_message_katcl(k, KATCP_LEVEL_WARN, label, "saw an in progress despite write set being ready on job %s", rx->r_name);
                  break;
                default :
                  log_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to connect to %s: %s", rx->r_name, strerror(code));
                  update_state(ss, rx, RX_BAD);
                  break;
              }
            }
          }
          break;
        case RX_UP :

          if(FD_ISSET(fd, &fsw)){ /* flushing things */
            result = write_katcl(rx->r_line);
            if(result < 0){
              log_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to write to %s: %s", rx->r_name, strerror(error_katcl(rx->r_line)));
              update_state(ss, rx, RX_BAD);
            }
          }

          if(FD_ISSET(fd, &fsr)){ /* get things */
            result = read_katcl(rx->r_line);
            if(result){
              if(result < 0){
                log_message_katcl(k, KATCP_LEVEL_ERROR, label, "read from %s failed: %s", rx->r_name, strerror(error_katcl(rx->r_line)));
              } else {
                log_message_katcl(k, KATCP_LEVEL_WARN, label, "%s disconnected", rx->r_name);
              }
            }
          }

          while(have_katcl(rx->r_line) > 0){ /* compute */


            cmd = arg_string_katcl(rx->r_line, 0);
            if(cmd){
#ifdef DEBUG
              fprintf(stderr, "reading message <%s ...>\n", cmd);
#endif
              switch(cmd[0]){
                case KATCP_INFORM : 
                  if(info){
                    if(show == 0){
                      if(!strcmp(KATCP_VERSION_CONNECT_INFORM, cmd)){
                        break;
                      }
                      if(!strcmp(KATCP_VERSION_INFORM, cmd)){
                        break;
                      }
                      if(!strcmp(KATCP_BUILD_STATE_INFORM, cmd)){
                        break;
                      }
                    }
                    relay_katcl(rx->r_line, k);
                  }
                  break;
                case KATCP_REPLY : 

                  switch(cmd[1]){
                    case ' '  :
                    case '\n' : 
                    case '\r' :
                    case '\t' :
                    case '\\' :
                    case '\0' :
                      log_message_katcl(k, KATCP_LEVEL_ERROR, label, "unreasonable response message from %s", rx->r_name);
                      update_state(ss, rx, RX_BAD);
                      break;
                    default : 
                      ptr = cmd + 1;
                      if(strcmp(ptr, rx->r_match)){
                        log_message_katcl(k, KATCP_LEVEL_ERROR, label, "downstream %s returned response %s which was never requested", rx->r_name, ptr);
                        update_state(ss, rx, RX_BAD);
                      } else {
                        parm = arg_string_katcl(rx->r_line, 1);
                        if(parm){
                          if(strcmp(parm, KATCP_OK) == 0){
                            count++;
                            if(munge){
                              log_message_katcl(k, KATCP_LEVEL_INFO, label, "%s %s ok", rx->r_name, ptr);
                            } 
                            if(verbose > 1){
                              log_message_katcl(k, KATCP_LEVEL_TRACE, label, "request %s to %s returned ok", ptr, rx->r_name);
                            }
                            result = next_request(rx);
                            if(result){
                              if(result < 0){
                                sync_message_katcl(k, KATCP_LEVEL_ERROR, label, "unable to queue request %s to %s", ptr, rx->r_name);
                                update_state(ss, rx, RX_BAD);
                              } else {
                                update_state(ss, rx, RX_OK);
                              } 
                            }
                          } else {
                            if(munge){
                              extra = arg_string_katcl(rx->r_line, 2);
                              log_message_katcl(k, KATCP_LEVEL_ERROR, label, "%s %s %s (%s)", rx->r_name, ptr, parm, extra ? extra : "no extra information");
                            } 
                            if(verbose > 0){
                              log_message_katcl(k, KATCP_LEVEL_ERROR, label, "downstream %s unable to process %s with status %s (%s)", rx->r_name, cmd, parm, extra ? extra : "no extra information");
                            }
                            update_state(ss, rx, RX_FAIL);
                          }
                        } else {
                          log_message_katcl(k, KATCP_LEVEL_ERROR, label, "response %s without status from %s", cmd, rx->r_name);
                          update_state(ss, rx, RX_FAIL);
                        }
                      }
                      break;
                  }
                  break;
                case KATCP_REQUEST : 
                  log_message_katcl(k, KATCP_LEVEL_WARN, label, "encountered unanswerable request %s", cmd);
                  update_state(ss, rx, RX_BAD);
                  break;
                default :
                  if(once){
                    log_message_katcl(k, KATCP_LEVEL_WARN, label, "read malformed message %s from %s", cmd, rx->r_name);
                    once = 1;
                  }
                  break;
              }

            }
          }
          break;

        /* case RX_OK : */
        /* case RX_FAIL : */
        /* case RX_BAD : */
        default :
          break;
      }
    }
  }

  status = ss->s_status;

  destroy_set(ss);

  if(verbose){
    if(status > 0){
      log_message_katcl(k, KATCP_LEVEL_WARN, label, "command sequence failed after operation %d", count);
    } else {
      if(count > 0){
        log_message_katcl(k, KATCP_LEVEL_INFO, label, "%d operations ok", count);
      } else {
        log_message_katcl(k, KATCP_LEVEL_INFO, label, "did nothing successfully");
      }
    }
  }

  /* flush, allows us to get away with deferring writes to stdout */
  while(write_katcl(k) == 0);
  destroy_katcl(k, 0);

  return status;
}
Exemple #2
0
int upload_tbs(struct katcl_line *l, void *data)
{ 
  struct tbs_port_data *pd;
  int run, lfd, nfd, rr, wr, have;
  unsigned char buf[MTU];

  if (data == NULL)
    return -1;

  pd = data;
  if (pd == NULL)
    return -1;

  lfd = net_listen(NULL, pd->t_port, NETC_VERBOSE_ERRORS | NETC_VERBOSE_STATS);
  if (lfd < 0){
    return -1;
  }

  signal(SIGALRM, SIG_DFL);
  alarm(UPLOAD_TIMEOUT);

  nfd = accept(lfd, NULL, 0);
  close(lfd);

  if (nfd < 0){
    return -1;
  }
  
  for (run = 1; run > 0; ){

    rr = read(nfd, buf, MTU);

    if (rr == 0){
      run = rr;
      break;
    } else if (rr < 0){
      sync_message_katcl(l, KATCP_LEVEL_INFO, NULL, "%s: read failed while receiving bof file: %s", __func__, strerror(errno));
      append_string_katcl(l, KATCP_FLAG_FIRST | KATCP_FLAG_STRING | KATCP_FLAG_LAST, UPLOADFAIL);
      while(write_katcl(l) == 0);
      close(nfd);
      return -1;
    }

    have = 0;
    do {
      wr = write(pd->t_fd, buf+have, rr-have);
      switch(wr){
        case -1:
          switch(errno){
            case EAGAIN:
            case EINTR:
              break;
            default:
              sync_message_katcl(l, KATCP_LEVEL_INFO, NULL, "%s: WRITE FAILED %s", __func__, strerror(errno));
              append_string_katcl(l, KATCP_FLAG_FIRST | KATCP_FLAG_STRING | KATCP_FLAG_LAST, UPLOADFAIL);
              while(write_katcl(l) == 0);
              close(nfd);
              return-1;
          }
        case 0:
          sync_message_katcl(l, KATCP_LEVEL_INFO, NULL, "%s: WRITE FAILED %s", __func__, strerror(errno));
          append_string_katcl(l, KATCP_FLAG_FIRST | KATCP_FLAG_STRING | KATCP_FLAG_LAST, UPLOADFAIL);
          while(write_katcl(l) == 0);
          close(nfd);
          return-1;
        default:
          have += wr;
          sync_message_katcl(l, KATCP_LEVEL_DEBUG, NULL, "%s: wrote %d bytes to parent", __func__, wr);
          break;
      }
    } while(have < rr);

    pd->t_rsize += rr;

    sync_message_katcl(l, KATCP_LEVEL_INFO, NULL, "uploaded %d bytes", pd->t_rsize);
    alarm(UPLOAD_TIMEOUT);
  }
  
  append_string_katcl(l, KATCP_FLAG_FIRST | KATCP_FLAG_STRING | KATCP_FLAG_LAST, UPLOADCOMPLETE);
  while(write_katcl(l) == 0);
  close(nfd);

  alarm(0);

  return 0;
}
Exemple #3
0
int main(int argc, char **argv)
{
  char *app, *server, *match, *parm, *tmp, *cmd, *extra;
  int i, j, c, fd;
  int verbose, result, status, base, run, info, reply, display, max, prefix, timeout, fmt, pos, flags, munge, show;
  struct katcl_line *l, *k;
  fd_set fsr, fsw;
  struct timeval tv;
  
  server = getenv("KATCP_SERVER");
  if(server == NULL){
    server = "localhost";
  }
  
  info = 1;
  reply = 1;
  verbose = 1;
  i = j = 1;
  app = argv[0];
  base = (-1);
  timeout = 5;
  fmt = FMT_TEXT;
  pos = (-1);
  k = NULL;
  munge = 0;
  show = 1;

  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {

        case 'h' :
          usage(app);
          return 0;

        case 'v' : 
          verbose++;
          j++;
          break;
        case 'q' : 
          verbose = 0;
          info = 0;
          reply = 0;
          j++;
          break;
        case 'i' : 
          info = 1 - info;
          j++;
          break;
        case 'r' : 
          reply = 1 - reply;
          j++;
          break;
        case 'n' : 
          show = 0;
          j++;
          break;
        case 'k' : 
          k = create_katcl(STDOUT_FILENO);
          if(k == NULL){
            fprintf(stderr, "%s: unable to create katcp message logic\n", app);
            return 2;
          }
          j++;
          break;
        case 'a' :
          fmt = FMT_AUTO;
          j++;
          break;
        case 'x' :
          fmt = FMT_HEX;
          j++;
          break;
        case 'b' :
          fmt = FMT_BIN;
          j++;
          break;
        case 'm' :
          munge = 1;
          j++;
          break;

        case 's' :
        case 't' :
        case 'p' :

          j++;
          if (argv[i][j] == '\0') {
            j = 0;
            i++;
          }
          if (i >= argc) {
            fprintf(stderr, "%s: argument needs a parameter\n", app);
            return 2;
          }

          switch(c){
            case 's' :
              server = argv[i] + j;
              break;
            case 't' :
              timeout = atoi(argv[i] + j);
              break;
            case 'p' :
              pos = atoi(argv[i] + j);
              if(pos < 0){
                fprintf(stderr, "%s: position needs to be nonnegative, not %d\n", app, pos);
                return 2;
              }
              break;
          }

          i++;
          j = 1;
          break;

        case '-' :
          j++;
          break;
        case '\0':
          j = 1;
          i++;
          break;
        default:
          fprintf(stderr, "%s: unknown option -%c\n", app, argv[i][j]);
          return 2;
      }
    } else {
      base = i;
      i = argc;
    }
  }

  if(munge){
    if(k){
      reply = 1;
    }
  }

  if(base < 0){
    if(k){
      sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "no command given");
    }
    fprintf(stderr, "%s: need a command to send (use -h for help)\n", app);
    return 2;
  }

  status = 1;

  flags = 0;
  if(verbose > 0){
    flags = NETC_VERBOSE_ERRORS;
    if(verbose > 1){
      flags = NETC_VERBOSE_STATS;
    }
  }

  fd = net_connect(server, 0, flags);
  if(fd < 0){
    if(k){
      sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "unable to connect to %s", server);
    }
    return 2;
  }

  l = create_katcl(fd);
  if(l == NULL){
    if(k){
      sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "unable to create katcp parser");
    }
    fprintf(stderr, "%s: unable to create katcp parser\n", app);
    return 2;
  }

  i = base;
  match = NULL;
  flags = ((i + 1) < argc) ? KATCP_FLAG_FIRST : (KATCP_FLAG_FIRST | KATCP_FLAG_LAST);
  switch(argv[i][0]){
    case KATCP_REQUEST :
      match = argv[i] + 1;
      /* FALL */
    case KATCP_INFORM :
    case KATCP_REPLY  :
      append_string_katcl(l, flags, argv[i]);
    break;
    default :
      match = argv[i];
      append_args_katcl(l, flags, "%c%s", KATCP_REQUEST, argv[i]);
    break;
  }
  i++;
  while(i < argc){
    tmp = argv[i];
    i++;
    flags = (i < argc) ? 0 : KATCP_FLAG_LAST;
    if(load_arg(l, tmp, fmt, flags) < 0){
      if(k){
        sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "unable to load argument %d", i);
      }
      fprintf(stderr, "%s: unable to load argument %d\n", app, i);
      return 2;
    }
  }

  if(match){
    for(prefix = 0; (match[prefix] != '\0') && (match[prefix] != ' '); prefix++);
#ifdef DEBUG
    fprintf(stderr, "debug: checking prefix %d of %s\n", prefix, match);
#endif
  } else {
    prefix = 0; /* pacify -Wall, prefix only used if match is set */
  }

  /* WARNING: logic a bit intricate */

  for(run = 1; run;){

    FD_ZERO(&fsr);
    FD_ZERO(&fsw);

    if(match){ /* only look for data if we need it */
      FD_SET(fd, &fsr);
    }

    if(flushing_katcl(l)){ /* only write data if we have some */
      FD_SET(fd, &fsw);
    }

    tv.tv_sec  = timeout;
    tv.tv_usec = 0;

    result = select(fd + 1, &fsr, &fsw, NULL, &tv);
    switch(result){
      case -1 :
        switch(errno){
          case EAGAIN :
          case EINTR  :
            continue; /* WARNING */
          default  :
            if(k){
              sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "select failed: %s", strerror(errno));
            }
            return 2;
        }
        break;
      case  0 :
        if(k){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "request timed out after %d seconds", timeout);
        } 
        if(verbose){
          fprintf(stderr, "%s: no io activity within %d seconds\n", app, timeout);
        }
        /* could terminate cleanly here, but ... */
        return 2;
    }

    if(FD_ISSET(fd, &fsw)){
      result = write_katcl(l);
      if(result < 0){
        if(k){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "write failed: %s", strerror(errno));
        } 
        fprintf(stderr, "%s: write failed: %s\n", app, strerror(error_katcl(l)));
      	return 2;
      }
      if((result > 0) && (match == NULL)){ /* if we finished writing and don't expect a match then quit */
      	run = 0;
      }
    }

    if(FD_ISSET(fd, &fsr)){
      result = read_katcl(l);
      if(result){
        if(k){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCMD_NAME, "read failed: %s", (result < 0) ? strerror(error_katcl(l)) : "connection terminated");

        } 
        fprintf(stderr, "%s: read failed: %s\n", app, (result < 0) ? strerror(error_katcl(l)) : "connection terminated");
      	return 2;
      }
    }

    while(have_katcl(l) > 0){
      cmd = arg_string_katcl(l, 0);
      if(cmd){
        display = 0;
      	switch(cmd[0]){
          case KATCP_INFORM : 
            display = info;
            if(show == 0){
              if(!strcmp(KATCP_VERSION_CONNECT_INFORM, cmd)){
                display = 0;
              }
            }

            break;
          case KATCP_REPLY : 
            display = reply;
            parm = arg_string_katcl(l, 1);
            if(match){
              if(strncmp(match, cmd + 1, prefix) || ((cmd[prefix + 1] != '\0') && (cmd[prefix + 1] != ' '))){
                if(k){
                  sync_message_katcl(k, KATCP_LEVEL_WARN, KCPCMD_NAME, "encountered unexpected reply %s", cmd);
                } 
                fprintf(stderr, "%s: warning: encountered unexpected reply <%s>\n", app, cmd);
              } else {
              	if(parm && !strcmp(parm, KATCP_OK)){
              	  status = 0;
                }
              	run = 0;
              }
            }
            break;
          case KATCP_REQUEST : 
            if(k){
              sync_message_katcl(k, KATCP_LEVEL_WARN, KCPCMD_NAME, "encountered unanswerable request %s", cmd);
            } 
            fprintf(stderr, "%s: warning: encountered an unanswerable request <%s>\n", app, cmd);
            break;
          default :
            if(k){
              sync_message_katcl(k, KATCP_LEVEL_WARN, KCPCMD_NAME, "read malformed message %s", cmd);
            } 
            fprintf(stderr, "%s: read malformed message <%s>\n", app, cmd);
            break;
        }
        if(display){
#ifdef DEBUG
          fprintf(stderr, "need to display\n");
#endif
          if(k){
            if(munge && parm && (cmd[0] == KATCP_REPLY)){
              if(!strcmp(parm, KATCP_OK)){
                sync_message_katcl(k, KATCP_LEVEL_DEBUG, cmd + 1, KATCP_OK);
              } else {
                extra = arg_string_katcl(l, 2);
                sync_message_katcl(k, KATCP_LEVEL_WARN, cmd + 1, "%s (%s)", parm, extra ? extra : "no extra information");
              } 
            } else {
              relay_katcl(l, k);
            }
          } else {
            max = arg_count_katcl(l);
            if(pos < 0){
              for(i = 0; i < max; i++){
                if(print_arg(l, i, fmt) < 0){
                  fprintf(stderr, "%s: failed to print argument %d\n", app, i);
                  return 2;
                }
                fputc(((i + 1) == max) ? '\n' : ' ' , stdout);
              }
            } else {
              if(pos < max){
                i = pos;
                if(print_arg(l, i, fmt) < 0){
                  fprintf(stderr, "%s: failed to print argument %d\n", app, i);
                  return 2;
                }
              }
            }
          }
        }
      }
    }
  }

  destroy_katcl(l, 1);
  if(k){
    while(write_katcl(k) == 0);

    destroy_katcl(k, 0);
  }

  return status;
}
Exemple #4
0
int main(int argc, char **argv)
{
#define BUFFER 64
  char buffer[BUFFER];
  char *level, *app, *server, *output;
  int run, fd, i, j, c, verbose, attempts, detach, result, truncate, flags;
  struct katcl_parse *p;
  struct katcl_line *ls, *lo;
  struct sigaction sa;
  time_t now;
  struct tm *local;

  i = j = 1;
  app = argv[0];

  verbose = 0;
  attempts = 2;
  detach = 0;
  truncate = 0;

  server = getenv("KATCP_SERVER");
  if(server == NULL){
    server = "localhost";
  }

  output = NULL;
  level = NULL;

  flags = 0; /* placate -Wall */

  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {

        case 'h' :
          usage(app);
          return EX_OK;

        case 'v' : 
          verbose++;
          j++;
          break;

        case 'd' : 
          detach = 1;
          j++;
          break;

        case 'f' : 
          detach = 0;
          j++;
          break;

        case 't' : 
          truncate = 1;
          j++;
          break;

        case 'q' : 
          verbose = 0;
          j++;
          break;

        case 'l' :
        case 'o' :
        case 'a' :
        case 's' :

          j++;
          if (argv[i][j] == '\0') {
            j = 0;
            i++;
          }
          if (i >= argc) {
            fprintf(stderr, "%s: usage: argument needs a parameter\n", app);
            return EX_USAGE;
          }

          switch(c){
            case 'l' :
              level = argv[i] + j;
              break;
            case 'o' :
              output = argv[i] + j;
              break;
            case 'a' : 
              attempts = atoi(argv[i] + j);
              break;
            case 's' : 
              server = argv[i] + j;
              break;
          }

          i++;
          j = 1;
          break;

        case '-' :
          j++;
          break;
        case '\0':
          j = 1;
          i++;
          break;
        default:
          fprintf(stderr, "%s: usage: unknown option -%c\n", app, argv[i][j]);
          return EX_USAGE;
      }
    } else {
      if(output){
        fprintf(stderr, "%s: usage: unexpected extra argument %s (can only save to one file)\n", app, argv[i]);
        return EX_USAGE;
      } 
      output = argv[i];
      i++;
    }
  }

  if(detach){
    if(fork_parent() < 0){
      fprintf(stderr, "%s: unable to detach process\n", app);
      return EX_OSERR;
    }
  }

  sa.sa_handler = handle_signal;
#if 0
  sa.sa_flags = SA_RESTART;
#endif
  sa.sa_flags = 0;
  sigemptyset(&(sa.sa_mask));

  sigaction(SIGHUP, &sa, NULL);
  sigaction(SIGUSR1, &sa, NULL);
  sigaction(SIGUSR2, &sa, NULL);

  if(server == NULL){
    server = "localhost:7147";
  }

  if(level){
    log_changed = 1;
    log_level = log_to_code_katcl(level);
    if(log_level < 0){
      fprintf(stderr, "%s: usage: invalid initial log priority %s\n", app, level);
      return EX_USAGE;
    } 
  }

  if(output == NULL){
    if(detach == 1){
      fprintf(stderr, "%s: usage: need a filename as target\n", app);
      return EX_USAGE;
    }
    fd = STDOUT_FILENO;
  } else {
    flags = O_CREAT | O_WRONLY;
    if(truncate == 0){
      flags |= O_APPEND;
    }
    fd = open(output, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
    if(fd < 0){
      fprintf(stderr, "%s: unable to open file %s: %s\n", app, output, strerror(errno));
      return EX_OSERR;
    }
  }

  lo = create_katcl(fd);
  if(lo == NULL){
    fprintf(stderr, "%s: unable to allocate log state\n", app);
    return EX_OSERR;
  }


  /**********************/

  while((attempts-- > 0) && ((fd = net_connect(server, 0, 0)) < 0)){
    sleep(1);
  }

  if(attempts <= 0){
    sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "unable to connect to %s", server);
    return EX_UNAVAILABLE;
  }

  ls = create_katcl(fd);
  if(ls == NULL){
    sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "unable to allocate parser state");
    return EX_OSERR;
  }

  if(detach){
    fclose(stderr);
  }

  time(&now);
  local = localtime(&now);
  strftime(buffer, BUFFER - 1, "%Y-%m-%dT%H:%M:%S", local);

  sync_message_katcl(lo, KATCP_LEVEL_INFO, NAME, "monitor start for %s at %s", server, buffer);

  for(run = 1; run > 0;){

    if(log_reload > 0){
      if(output){
        fd = open(output, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
        if(fd >= 0){
          exchange_katcl(lo, fd);
        }
      }

      log_reload = 0;
    }
 
    /* WARNING: will only run after the next message - may have to interrupt syscall to get past this */
    if(log_changed > 0){

      level = log_to_string_katcl(log_level);
      if(level){

        p = create_parse_katcl();
        if(p){

          add_string_parse_katcl(p, KATCP_FLAG_STRING | KATCP_FLAG_FIRST, "?log-level");
          add_string_parse_katcl(p, KATCP_FLAG_STRING | KATCP_FLAG_LAST, level);

          append_parse_katcl(lo, p);

          /* dodgy refcount dealings: p is created with refcount = 0, so can only do write at end, otherwise may end up being deallocated */

          append_parse_katcl(ls, p);
          write_katcl(ls);

        }
      } else {
        sync_message_katcl(lo, KATCP_LEVEL_ERROR, NAME, "invalid log priority number %d", level);
      }

      log_changed = 0;
    }

    result = read_katcl(ls);
    if(result < 0){
      sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "read from network failed: %s", strerror(errno));
      return EX_OSERR;
    }

    if(result == 1){
      run = 0;
    }

    while(have_katcl(ls)){
      p = ready_katcl(ls);
      if(p){
        append_parse_katcl(lo, p);
      }
    }

    write_katcl(lo);
  }

  return EX_OK;
#undef BUFFER
}
Exemple #5
0
int main(int argc, char **argv)
{
  struct state *ss;
  struct child *cx;
  fd_set fsr, fsw;
  char *cmd;
  int i, j, c, mfd, fd, verbose, result, status;
  sigset_t mask_current, mask_previous;
  struct sigaction action_current, action_previous;
  pid_t pid;

  ss = create_state(STDOUT_FILENO);
  if(ss == NULL){
    return 4;
  }

#if 0
  char *app, *parm, *cmd, *copy, *ptr, *servers;
  int verbose, result, status, base, info, reply, timeout, pos, flags, show;
  int xmit, code;
  unsigned int len;
  
  info = 1;
  reply = 1;
  i = j = 1;
  app = argv[0];
  base = (-1);
  timeout = 5;
  pos = (-1);
  k = NULL;
  show = 1;
  parm = NULL;
#endif

  verbose = 1;
  i = j = 1;

  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {

        case 'h' :
          usage(argv[0]);
          return 0;

        case 'v' : 
          verbose++;
          j++;
          break;
        case 'q' : 
          verbose = 0;
          j++;
          break;

        case '-' :
          j++;
          break;
        case '\0':
          j = 1;
          i++;
          break;

        default:
          sync_message_katcl(ss->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "unknown option -%c", argv[i][j]);
          return 2;
      }
    } else {
#ifdef DEBUG
      fprintf(stderr, "about to start <%s>\n", argv[i]);
#endif
      if(string_launch_child(ss, argv[i]) < 0){
        sync_message_katcl(ss->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "unable to start <%s>", argv[i]);
        return 4;
      }
      i++;
    }
  }

  sigprocmask(SIG_SETMASK, NULL, &mask_current);
  sigaddset(&mask_current, SIGCHLD);

  action_current.sa_handler = &handle_child;
  action_current.sa_flags = SA_NOCLDSTOP;
  sigfillset(&(action_current.sa_mask));
  sigaction(SIGCHLD, &action_current, &action_previous);

  sigprocmask(SIG_SETMASK, &mask_current, &mask_previous);

  sigemptyset(&mask_current);
#if 0
  sigaddset(&mask_current, SIGTERM);
#endif

  for(ss->s_finished = 0; ss->s_finished < ss->s_count;){


    mfd = 0;

    FD_ZERO(&fsr);
    FD_ZERO(&fsw);

    if(flushing_katcl(ss->s_up)){
      mfd = fileno_katcl(ss->s_up);
      FD_SET(mfd, &fsw);
    }

    for(i = 0; i < ss->s_count; i++){
      cx = ss->s_vector[i];
      if(cx->c_line){
        fd = fileno_katcl(cx->c_line);
        if(fd > mfd){
          mfd = fd;
        }
        FD_SET(fd, &fsr);
      } 
    }

    result = pselect(mfd + 1, &fsr, &fsw, NULL, NULL, &mask_current);
#ifdef DEBUG
    fprintf(stderr, "select returns %d\n", result);
#endif
    switch(result){
      case -1 :
        switch(errno){
          case EAGAIN :
          case EINTR  :
            continue; /* WARNING */
          default  :
            sync_message_katcl(ss->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "select failed: %s", strerror(errno));
            return 4;
        }
        break;
      case  0 :
        sync_message_katcl(ss->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "requests timed out despite having no timeout");
        /* could terminate cleanly here, but ... */
        return 4;
    }


    fd = fileno_katcl(ss->s_up);
    if(FD_ISSET(fd, &fsw)){
      result = write_katcl(ss->s_up);
    }

    for(i = 0; i < ss->s_count; i++){
      cx = ss->s_vector[i];
      if(cx->c_line){
        fd = fileno_katcl(cx->c_line);

        if(FD_ISSET(fd, &fsr)){ /* get things */
          result = read_katcl(cx->c_line);
          if(result){
            if(result < 0){
              sync_message_katcl(ss->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "read failed: %s", strerror(error_katcl(cx->c_line)));
            } else {
              if(cx->c_pid > 0){
                log_message_katcl(ss->s_up, KATCP_LEVEL_DEBUG, KCPCON_NAME, "subordinate job %u ended", cx->c_pid);
              }
            }
            destroy_katcl(cx->c_line, 1);
            cx->c_line = NULL;
            ss->s_finished++;
            continue; /* WARNING */
          }
        }

        while(have_katcl(cx->c_line) > 0){ /* compute */
          cmd = arg_string_katcl(cx->c_line, 0);
          if(cmd){
#ifdef DEBUG
            fprintf(stderr, "reading message <%s ...>\n", cmd);
#endif
            switch(cmd[0]){
              case KATCP_INFORM : 
#if 0
                if(!strcmp(KATCP_VERSION_CONNECT_INFORM, cmd)){
                }
                if(!strcmp(KATCP_VERSION_INFORM, cmd)){
                }
                if(!strcmp(KATCP_BUILD_STATE_INFORM, cmd)){
                }
#endif
                relay_katcl(cx->c_line, ss->s_up);
                break;
            }
          }
        }
      }
    }

    /* the position of this logic is rather intricate */
    if(got_child_signal){
      got_child_signal = 0;
      while((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0){
        for(i = 0; i < ss->s_count; i++){
          cx = ss->s_vector[i];
          if(cx->c_pid == pid){

            if (WIFEXITED(status)) {
              result = WEXITSTATUS(status);
              log_message_katcl(ss->s_up, KATCP_LEVEL_DEBUG, KCPCON_NAME, "subordinate job[%u] %u exited with code %d", i, cx->c_pid, result);
              cx->c_status = (result > 4) ? 4 : result;
            } else if (WIFSIGNALED(status)) {
              result = WTERMSIG(status);
              log_message_katcl(ss->s_up, KATCP_LEVEL_WARN, KCPCON_NAME, "subordinate job[%u] %u killed by signal %d", i, cx->c_pid, result);
              cx->c_status = 4;
            } else {
              log_message_katcl(ss->s_up, KATCP_LEVEL_WARN, KCPCON_NAME, "subordinate job[%u] %u return unexpected status %d", i, cx->c_pid, status);
              cx->c_status = 4;
            }

            if(cx->c_status > ss->s_code){
              ss->s_code = cx->c_status;
            }

            cx->c_pid = (-1);
          }
        }
      }
    }
  }

  /* force drain */
  while(write_katcl(ss->s_up) == 0);

  result = ss->s_code;

  destroy_state(ss);

  /* WARNING: pointlessly fussy */
  sigaction(SIGCHLD, &action_previous, NULL);
  sigprocmask(SIG_BLOCK, &mask_previous, NULL);

  return result;
}
Exemple #6
0
int string_launch_child(struct state *s, char *string)
{
  char **vector, **tmp;
  char *t;
  unsigned int i, v, j, d, ws;
  int run;

  vector = NULL;
  j = 0; 
  i = 0;
  ws = 1;
  v = 0;

  for(run = 1; run > 0;){
    switch(string[i]){
      case '\0'  :
        run = 0;
        /* fall */
      case ' '   :
      case '\t'  :
        if(ws == 0){
          ws = 1;
          tmp = realloc(vector, sizeof(char *) * (v + 2));
          if(tmp == NULL){
            run = (-1);
          } else {
            vector = tmp;
            d = i - j;
            t = malloc(sizeof(char) * (d + 1));
            if(t == NULL){
              run = (-1);
            } else {
              strncpy(t, string + j, d);
              t[d] = '\0';
              vector[v] = t;
              v++;
              vector[v] = NULL;
            }
          }
        }
        i++;
        break;
      default :
        if(ws){
          j = i;
          ws = 0;
        }
        i++;
      break;
    }
  }

  if(vector == NULL){
    sync_message_katcl(s->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "no command found in string <%s>", string);
    return -1;
  }


  if(run < 0){
    sync_message_katcl(s->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "allocation error while decomposing %s", string);
  } else {
#ifdef DEBUG
  fprintf(stderr, "have vector <%s ...> of %u entries\n", vector[0], v);
#endif
    run = launch_child(s, vector);
  }

  if(vector){
    for(i = 0; i < v; i++){
      if(vector[i]){
        free(vector[i]);
        vector[i] = NULL;
      }
    }
    free(vector);
  }

  return run;
}
Exemple #7
0
int launch_child(struct state *s, char **vector)
{
  int fds[2], fd;
  pid_t pid;
  struct child **tmp;
  struct child *c;
  struct katcl_line *k;
  unsigned int i;

  tmp = realloc(s->s_vector, sizeof(struct child *) * (s->s_count + 1));
  if(tmp == NULL){
    return -1;
  }

  s->s_vector = tmp;

  c = malloc(sizeof(struct child));
  if(c == NULL){
    return -1;
  }

  c->c_pid = 0;
  c->c_line = NULL;
  c->c_status = 0;

  if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0){
    sync_message_katcl(s->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "unable to allocate socketpair: %s", strerror(errno));
    destroy_child(c);
    return -1;
  }

  pid = fork();
  if(pid < 0){
    sync_message_katcl(s->s_up, KATCP_LEVEL_ERROR, KCPCON_NAME, "unable to fork: %s", strerror(errno));
    close(fds[0]);
    close(fds[1]);
    destroy_child(c);
    return -1;
  }

  if(pid > 0){
    c->c_pid = pid;

    close(fds[0]);
    fcntl(fds[1], F_SETFD, FD_CLOEXEC);

    c->c_line = create_katcl(fds[1]);
    if(c->c_line == NULL){
      destroy_child(c);
    }

    s->s_vector[s->s_count] = c;
    s->s_count++;

    return 0;
  }

  /* WARNING: can not return from code below, have to exit() */

  close(fds[1]);

  fd = fds[0];

  k = create_katcl(fd);

  for(i = STDIN_FILENO; i <= STDERR_FILENO; i++){
    if(fd != i){
      if(dup2(fd, i) < 0){
        if(k){
          sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCON_NAME, "unable to duplicate fd %d to replace %d: %s", fd, i, strerror(errno));
        }
        exit(1);
      }
    }
  }

  execvp(vector[0], vector);

  if(k){
    sync_message_katcl(k, KATCP_LEVEL_ERROR, KCPCON_NAME, "unable to run %s: %s", vector[0], strerror(errno));
  }

  exit(1);
  return -1;
}