Beispiel #1
0
static void
_sendto (cbuf_t cbuf, int fd, struct sockaddr_in *destaddr)
{
  int n, rv;
  uint8_t buf[IPMIPOWER_PACKET_BUFLEN];

  if ((n = cbuf_read (cbuf, buf, IPMIPOWER_PACKET_BUFLEN)) < 0)
    {
      IPMIPOWER_ERROR (("cbuf_read: %s", fd, strerror (errno)));
      exit (EXIT_FAILURE);
    }

  if (n == IPMIPOWER_PACKET_BUFLEN)
    {
      IPMIPOWER_ERROR (("cbuf_read: buffer full"));
      exit (EXIT_FAILURE);
    }

  do 
    {
      if (cmd_args.common_args.driver_type == IPMI_DEVICE_LAN)
	rv = ipmi_lan_sendto (fd,
			      buf,
			      n,
			      0,
			      (struct sockaddr *)destaddr,
			      sizeof (struct sockaddr_in));
      else
	{
	  if (ipmi_is_ipmi_1_5_packet (buf, n))
	    rv = ipmi_lan_sendto (fd,
				  buf,
				  n,
				  0,
				  (struct sockaddr *)destaddr,
				  sizeof (struct sockaddr_in));
	  else
	    rv = ipmi_rmcpplus_sendto (fd,
				       buf,
				       n,
				       0,
				       (struct sockaddr *)destaddr,
				       sizeof (struct sockaddr_in));
	}
    } while (rv < 0 && errno == EINTR);

  if (rv < 0)
    {
      IPMIPOWER_ERROR (("ipmi_lan/rmcpplus_sendto: %s", strerror (errno)));
      exit (EXIT_FAILURE);
    }

  /* cbuf should be empty now */
  if (!cbuf_is_empty (cbuf))
    {
      IPMIPOWER_ERROR (("cbuf not empty"));
      exit (EXIT_FAILURE);
    }
}
Beispiel #2
0
cbsize_t cbuf_read (cbuf_t* cb, char* data, cbsize_t desired_len)
{
    // cb->read must always be equal when using this function
    // (do not use cbuf_*_ptr)

    cbsize_t want = desired_len;
    cbsize_t ret = 0;
    while (want && !cbuf_is_empty(cb))
    {
        cbsize_t readable_len = cb->read >= cb->write?
                                cb->size - cb->read:
                                cb->write - cb->read;
        cbsize_t chunk = (want > readable_len)? readable_len: want;
        memcpy(data + ret, cb->buf + cb->read, chunk);
        ret += chunk;
        want -= chunk;
        if ((cb->read += chunk) == cb->size)
            cb->read = 0;
        if ((cb->empty = cb->allread = (cb->read == cb->write)))
            do_flush(cb); // bigger_chunk, less loop
    }
    return ret;
}
Beispiel #3
0
/* _poll_loop
 * - poll on all descriptors
 */
static void
_poll_loop (int non_interactive)
{
  int nfds = 0;
  struct pollfd *pfds = NULL;
  int extra_fds;

  /* number of fds for stdin and stdout we'll need when polling
   *
   * Right now, always poll stdout.  When non-interactive,
   * don't need stdin
   */
  extra_fds = 1 + (non_interactive ? 0 : 1);

  while (non_interactive || ipmipower_prompt_process_cmdline ())
    {
      int i, num, timeout;
      int powercmd_timeout = -1;
      int ping_timeout = -1;

      /* If there are no pending commands before this call,
       * powercmd_timeout will not be set, leaving it at -1
       */
      num = ipmipower_powercmd_process_pending (&powercmd_timeout);
      if (non_interactive && !num)
        break;

      /* ping timeout is always set if cmd_args.ping_interval > 0 */
      ipmipower_ping_process_pings (&ping_timeout);

      if (cmd_args.ping_interval)
        {
          if (powercmd_timeout == -1)
            timeout = ping_timeout;
          else
            timeout = (ping_timeout < powercmd_timeout) ?
          ping_timeout : powercmd_timeout;
        }
      else
        timeout = powercmd_timeout;

      /* achu: I always wonder if this poll() loop could be done far
       * more elegantly and efficiently without all this crazy
       * indexing, perhaps through a callback/event mechanism.  It'd
       * probably be more efficient, since most callback/event based
       * models have min-heap like structures inside for determining
       * what things timed out. Overall though, I don't think the O(n)
       * (n being hosts/fds) processing is really that inefficient for
       * this particular application and is not worth going back and
       * changing.  By going to a callback/event mechanism, there will
       * still be some O(n) activities within the code, so I am only
       * going to create a more efficient O(n) poll loop.
       */

      /* Has the number of hosts changed? */
      if (nfds != (ics_len*2) + extra_fds)
        {
          /* The "*2" is for each host's two fds, one for ipmi
           * (ipmi_fd) and one for rmcp (ping_fd).
           */
          nfds = (ics_len*2) + extra_fds;
          free (pfds);

          if (!(pfds = (struct pollfd *)malloc (nfds * sizeof (struct pollfd))))
            {
              IPMIPOWER_ERROR (("malloc: %s", strerror (errno)));
              exit (EXIT_FAILURE);
            }
        }

      for (i = 0; i < ics_len; i++)
        {
          pfds[i*2].fd = ics[i].ipmi_fd;
          pfds[i*2+1].fd = ics[i].ping_fd;
          pfds[i*2].events = pfds[i*2+1].events = 0;
          pfds[i*2].revents = pfds[i*2+1].revents = 0;

          pfds[i*2].events |= POLLIN;
          if (!cbuf_is_empty (ics[i].ipmi_out))
            pfds[i*2].events |= POLLOUT;

          if (!cmd_args.ping_interval)
            continue;

          pfds[i*2+1].events |= POLLIN;
          if (!cbuf_is_empty (ics[i].ping_out))
            pfds[i*2+1].events |= POLLOUT;
        }

      if (!non_interactive)
	{
	  pfds[nfds-2].fd = STDIN_FILENO;
	  pfds[nfds-2].events = POLLIN;
	  pfds[nfds-2].revents = 0;
	}
      pfds[nfds-1].fd = STDOUT_FILENO;
      if (!cbuf_is_empty (ttyout))
        pfds[nfds-1].events = POLLOUT;
      else
        pfds[nfds-1].events = 0;
      pfds[nfds-1].revents = 0;

      ipmipower_poll (pfds, nfds, timeout);

      for (i = 0; i < ics_len; i++)
        {
          if (pfds[i*2].revents & POLLERR)
            {
              IPMIPOWER_DEBUG (("host = %s; IPMI POLLERR", ics[i].hostname));
              /* See comments in _ipmi_recvfrom() regarding ECONNRESET/ECONNREFUSED */
              _recvfrom (ics[i].ipmi_in, ics[i].ipmi_fd, &(ics[i].destaddr));
            }
          else
            {
              if (pfds[i*2].revents & POLLIN)
                _recvfrom (ics[i].ipmi_in, ics[i].ipmi_fd, &(ics[i].destaddr));
              
              if (pfds[i*2].revents & POLLOUT)
                _sendto (ics[i].ipmi_out, ics[i].ipmi_fd, &(ics[i].destaddr));
            }

          if (!cmd_args.ping_interval)
            continue;

          if (pfds[i*2+1].revents & POLLERR)
            {
              IPMIPOWER_DEBUG (("host = %s; PING_POLLERR", ics[i].hostname));
              _recvfrom (ics[i].ping_in, ics[i].ping_fd, &(ics[i].destaddr));
            }
          else
            {
              if (pfds[i*2+1].revents & POLLIN)
                _recvfrom (ics[i].ping_in, ics[i].ping_fd, &(ics[i].destaddr));
              
              if (pfds[i*2+1].revents & POLLOUT)
                _sendto (ics[i].ping_out, ics[i].ping_fd, &(ics[i].destaddr));
            }
        }

      if (!non_interactive && (pfds[nfds-2].revents & POLLIN))
        {
          int n, dropped = 0;

          if ((n = cbuf_write_from_fd (ttyin, STDIN_FILENO, -1, &dropped)) < 0)
            {
              IPMIPOWER_ERROR (("cbuf_write_from_fd: %s", strerror (errno)));
              exit (EXIT_FAILURE);
            }

          /* achu: If you are running ipmipower in co-process mode
           * with powerman, this error condition will probably be hit
           * with the file descriptor STDIN_FILENO.  The powerman
           * daemon is usually closed by /etc/init.d/powerman stop,
           * which kills a process through a signal.  Thus, powerman
           * closes stdin and stdout pipes to ipmipower and the call
           * to cbuf_write_from_fd will give us an EOF reading.  We'll
           * consider this EOF an "ok" error.  No need to output an
           * error message.
           */
          if (!n)
            exit (EXIT_FAILURE);
          
          if (dropped)
            IPMIPOWER_DEBUG (("cbuf_write_from_fd: read dropped %d bytes", dropped));
        }

      if (!cbuf_is_empty (ttyout) && (pfds[nfds-1].revents & POLLOUT))
        {
          if (cbuf_read_to_fd (ttyout, STDOUT_FILENO, -1) < 0)
            {
              IPMIPOWER_ERROR (("cbuf_read_to_fd: %s", strerror (errno)));
              exit (EXIT_FAILURE);
            }
        }
    }

  free (pfds);
}
Beispiel #4
0
static void
_recvfrom (cbuf_t cbuf, int fd, struct sockaddr_in *srcaddr)
{
  int n, rv, dropped = 0;
  uint8_t buf[IPMIPOWER_PACKET_BUFLEN];
  struct sockaddr_in from;
  unsigned int fromlen = sizeof (struct sockaddr_in);

  do
    {
      /* For receive side, ipmi_lan_recvfrom and
       * ipmi_rmcpplus_recvfrom are identical.  So we just use
       * ipmi_lan_recvfrom for both.
       *
       * In event of future change, should use util functions
       * ipmi_is_ipmi_1_5_packet or ipmi_is_ipmi_2_0_packet
       * appropriately.
       */
      rv = ipmi_lan_recvfrom (fd,
                              buf,
                              IPMIPOWER_PACKET_BUFLEN,
                              0,
                              (struct sockaddr *)&from,
                              &fromlen);
    } while (rv < 0 && errno == EINTR);

  /* achu & hliebig:
   *
   * Premise from ipmitool (http://ipmitool.sourceforge.net/)
   *
   * On some OSes (it seems Unixes), the behavior is to not return
   * port denied errors up to the client for UDP responses (i.e. you
   * need to timeout).  But on some OSes (it seems Windows), the
   * behavior is to return port denied errors up to the user for UDP
   * responses via ECONNRESET or ECONNREFUSED.
   *
   * If this were just the case, we could return or handle errors
   * properly and move on.  However, it's not the case.
   *
   * According to Ipmitool, on some motherboards, both the OS and the
   * BMC are capable of responding to an IPMI request.  That means you
   * can get an ECONNRESET or ECONNREFUSED, then later on, get your
   * real IPMI response.
   *
   * Our solution is copied from Ipmitool, we'll ignore some specific
   * errors and try to read again.
   *
   * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get
   * an IPMI response later, the recvfrom later on gets the packet we
   * want.
   *
   * If the ECONNREFUSED or ECONNRESET is from the OS but there is no
   * BMC (or IPMI disabled, etc.), just do the recvfrom again to
   * eventually get a timeout, which is the behavior we'd like.
   */
  if (rv < 0
      && (errno == ECONNRESET
          || errno == ECONNREFUSED))
    {
      IPMIPOWER_DEBUG (("ipmi_lan_recvfrom: connection refused: %s", strerror (errno)));
      return;
    }

  if (rv < 0)
    {
      IPMIPOWER_ERROR (("ipmi_lan_recvfrom: %s", strerror (errno)));
      exit (EXIT_FAILURE);
    }

  if (!rv)
    {
      IPMIPOWER_ERROR (("ipmi_lan_recvfrom: EOF"));
      exit (EXIT_FAILURE);
    }

  /* Don't store if this packet is strange for some reason */
  if (from.sin_family != AF_INET
      || from.sin_addr.s_addr != srcaddr->sin_addr.s_addr)
    return;

  /* cbuf should be empty, but if it isn't, empty it */
  if (!cbuf_is_empty (cbuf))
    {
      IPMIPOWER_DEBUG (("cbuf not empty, draining"));
      do
        {
          uint8_t tempbuf[IPMIPOWER_PACKET_BUFLEN];
          
          if (cbuf_read (cbuf, tempbuf, IPMIPOWER_PACKET_BUFLEN) < 0)
            {
              IPMIPOWER_ERROR (("cbuf_read: %s", strerror (errno)));
              exit (EXIT_FAILURE);
            }
        } while(!cbuf_is_empty (cbuf));
    }

  if ((n = cbuf_write (cbuf, buf, rv, &dropped)) < 0)
    {
      IPMIPOWER_ERROR (("cbuf_write: %s", strerror (errno)));
      exit (EXIT_FAILURE);
    }

  if (n != rv)
    {
      IPMIPOWER_ERROR (("cbuf_write: rv=%d n=%d", rv, n));
      exit (EXIT_FAILURE);
    }

  if (dropped)
    IPMIPOWER_DEBUG (("cbuf_write: read dropped %d bytes", dropped));
}
Beispiel #5
0
static int
_pstdout_output_finish(pstdout_state_t pstate)
{
    int pstate_mutex_locked = 0;
    int rc, rv = -1;

    assert(pstate);
    assert(pstate->magic == PSTDOUT_STATE_MAGIC);
    assert(pstate->p_stdout);
    assert(pstate->p_stderr);

    if ((rc = pthread_mutex_lock(&(pstate->mutex))))
    {
        if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD)
            fprintf(stderr, "pthread_mutex_lock: %s\n", strerror(rc));
        pstdout_errnum = PSTDOUT_ERR_INTERNAL;
        goto cleanup;
    }
    pstate_mutex_locked++;

    /* If there is remaining junk in the cbufs, write a "\n" to it so we
     * finish off the line and get it flushed out.
     */
    if (!cbuf_is_empty(pstate->p_stdout))
        _pstdout_print_wrapper(pstate, 1, stdout, "\n");

    if (!cbuf_is_empty(pstate->p_stderr))
        _pstdout_print_wrapper(pstate, 1, stderr, "\n");

    if (_pstdout_output_buffer_data(pstate,
                                    stdout,
                                    &(pstate->buffer_stdout),
                                    &(pstate->buffer_stdout_len),
                                    PSTDOUT_OUTPUT_STDOUT_PREPEND_HOSTNAME,
                                    PSTDOUT_OUTPUT_BUFFER_STDOUT,
                                    PSTDOUT_OUTPUT_STDOUT_CONSOLIDATE,
                                    pstdout_consolidated_stdout,
                                    &pstdout_consolidated_stdout_mutex) < 0)
        goto cleanup;

    if (_pstdout_output_buffer_data(pstate,
                                    stderr,
                                    &(pstate->buffer_stderr),
                                    &(pstate->buffer_stderr_len),
                                    PSTDOUT_OUTPUT_STDERR_PREPEND_HOSTNAME,
                                    PSTDOUT_OUTPUT_BUFFER_STDERR,
                                    PSTDOUT_OUTPUT_STDERR_CONSOLIDATE,
                                    pstdout_consolidated_stderr,
                                    &pstdout_consolidated_stderr_mutex) < 0)
        goto cleanup;

    /* Only output from internal to pstdout is allowed */
    pstate->no_more_external_output = 1;
    rv = 0;

cleanup:
    if (pstate_mutex_locked)
    {
        if ((rc = pthread_mutex_unlock(&(pstate->mutex))))
        {
            if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD)
                fprintf(stderr, "pthread_mutex_unlock: %s\n", strerror(rc));
            /* Don't change error code, just move on */
        }
    }
    return rv;
}