Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

ziomon_mgr.c

/*
 * FCP adapter trace utility
 *
 * Central message collection tool
 *
 * Copyright IBM Corp. 2008
 * Author(s): Stefan Raspl <raspl@linux.vnet.ibm.com>
 */

#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <linux/types.h>
#include <limits.h>
#include <time.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>

#include "ziomon_util.h"
#include "ziomon_tools.h"
#include "ziomon_dacc.h"
#include "ziomon_zfcpdd.h"
#include "zt_common.h"
#include "ziomon_msg_tools.h"
#include "blkiomon.h"



const char *toolname = "ziomon_mgr";
int verbose=0;
static int keep_running = 1;


struct options {
      char                     *msg_q_path;
      int               msg_q_id;
      int               msg_q;
      long              msg_id_utilization;
      long              msg_id_ioerr;
      long              msg_id_blkiomon;
      long              msg_id_zfcpdd;
      int               estimate;
      int               interval_length;
      int               force;
      long                    version;
      char                     *outfile_name;
      char                     *outfile_name_agg;
      FILE                     *outfile;
      FILE               *outfile_agg;
      struct aggr_data  agg_data;
      long              size_limit;
      short             wrapped;
      struct file_header      f_hdr;
};


static void init_opts(struct options *opts)
{
      opts->msg_q_path = NULL;
      opts->msg_q_id = -1;
      opts->msg_q = -1;
      opts->msg_id_blkiomon = LONG_MIN;
      opts->msg_id_utilization = LONG_MIN;
      opts->msg_id_ioerr = LONG_MIN;
      opts->msg_id_zfcpdd = LONG_MIN;
      opts->outfile_name = NULL;
      opts->outfile_name_agg = NULL;
      opts->outfile = NULL;
      opts->outfile_agg = NULL;
      opts->size_limit = LONG_MAX;
      opts->wrapped = 0;
      opts->interval_length = -1;
      opts->force = 0;
      opts->estimate = 0;
      opts->version = 3;
}


static void deinit_opts(struct options *opts)
{
      if (opts->msg_q >= 0) {
            verbose_msg("shutting down message queue\n");
            if (msgctl(opts->msg_q, IPC_RMID, 0) == -1)
                  fprintf(stderr, "%s: Error encountered"
                        " while shutting down message queue: %s\n",
                        toolname, strerror(errno));
      }
      if (opts->outfile)
            fclose(opts->outfile);
      free(opts->outfile_name);
      free(opts->outfile_name_agg);
      if (opts->outfile_agg) {
            fclose(opts->outfile_agg);
            discard_aggr_data_struct(&opts->agg_data);
      }
}


static const char help_text[] =
  "Usage: ziomon_mgr [-h] [-v] [-V] [-e] [-f] [-l <size>] [-x <version>]"
  " -o <filename> -i <length>\n"
  "                  -Q <msgq-path> -q <msgq-id> -u <util-id> -r <ioerr-id>\n"
  "                  -b <blkiomon-id> -z <ziomon_zfcpdd-id>\n"
  "Start the message server for the ziomon framework.\n"
  "\n"
  "-h, --help              Print usage information and exit.\n"
  "-v, --version           Print version information and exit.\n"
  "-V, --verbose           Be verbose.\n"
  "-e, --binary-offsets    Print a list of binary data structure"
                         " sizes and exit.\n"
  "-f, --force             Force message queue creation.\n"
  "-i, --interval-length   Specify interval length in seconds.\n"
  "-Q, --msg-queue-name    Specify the message queue path name.\n"
  "-q, --msg-queue-id      Specify the message queue id.\n"
  "-u, --util-id           Specify the id for utilization messages from\n"
  "                        ziomon_util.\n"
  "-r, --ioerr-id          Specify the id for ioerr messages from"
                     " ziomon_util.\n"
  "-b, --blkiomon-id       Specify the id for messages from blkiomon.\n"
  "-z, --ziomon-zfcpdd-id  Specify the id for messages from ziomon_zfcpdd.\n"
  "-o, --output            Specify the name of the output file(s).\n"
  "-l, --size-limit        Maximum size of data collected in MB.\n"
  "-x, --enforce-version   Enforce specific version for .log and .agg files.\n";

static void print_help(void)
{
        fprintf(stdout, "%s", help_text);
}


static void print_version(void)
{
        fprintf(stdout, "%s: ziomon manager, version %s\n"
               "Copyright IBM Corp. 2008\n",
               toolname, RELEASE_STRING);
}


static int setup_msg_q(struct options *opts)
{
      key_t util_q;
      int flags;

      util_q = ftok(opts->msg_q_path, opts->msg_q_id);

      if (util_q == -1) {
            fprintf(stderr, "%s: Cannot create"
                  " message queue with path %s and id %d: %s\n",
                  toolname, opts->msg_q_path, opts->msg_q_id, strerror(errno));
            return -1;
      }

      verbose_msg("message queue key is %d\n", util_q);

      flags = IPC_CREAT | S_IRWXU;
      if (!opts->force)
            flags |= IPC_EXCL;
      opts->msg_q = msgget(util_q, flags);
      if (opts->msg_q < 0) {
            fprintf(stderr, "%s: Could not open message queue"
                  ": %s\n", toolname, strerror(errno));
            if (!opts->force)
                  fprintf(stderr, "%s: Retry using the 'force'"
                        " option\n", toolname);
            return -1;
      }
      verbose_msg("message queue id is %d\n", opts->msg_q);

      return 0;
}


static int add_to_aggregated(struct message **msgs, int num_msgs,
                       struct options *opts)
{
      int i;

      if (!opts->outfile_agg) {
            opts->outfile_agg = fopen(opts->outfile_name_agg, "w+");
            if (!opts->outfile_agg) {
                  fprintf(stderr, "%s: Could not open file"
                        " for aggregated data: %s\n", toolname,
                        strerror(errno));
                  return -1;
            }
            init_aggr_data_struct(&opts->agg_data);
      }

      /* aggregate data */
      for (i = 0; i < num_msgs; ++i) {
            if (add_to_agg(&opts->agg_data, msgs[i], &opts->f_hdr))
                  return -1;
            discard_msg(msgs[i]);
            free(msgs[i]);
      }
      free(msgs);

      /* write back to file */
      conv_aggr_data_msg_data_to_BE(&opts->agg_data);
      i = write_aggr_file(opts->outfile_agg, &opts->agg_data);
      conv_aggr_data_msg_data_from_BE(&opts->agg_data);

      return i;
}

static int compare_msg_ids(const void *a, const void *b)
{
      return (*(long*)b - *(long*)a);
}

static int check_msg_ids(struct options *opts)
{
      int i;
      long msg_ids[4];

      msg_ids[0] = opts->msg_id_utilization;
      msg_ids[1] = opts->msg_id_ioerr;
      msg_ids[2] = opts->msg_id_blkiomon;
      msg_ids[3] = opts->msg_id_zfcpdd;

      qsort(msg_ids, 4, sizeof(long), compare_msg_ids);

      for (i = 0; i < 4; ++i) {
            if (msg_ids[i] <= 0) {
                  fprintf(stderr, "%s: ids for messages must be"
                        " greater than 0\n", toolname);
                  return -1;
            }
            if (i != 0 && msg_ids[i] == msg_ids[i-1]) {
                  fprintf(stderr, "%s: ids for messages must be"
                        " different from another\n", toolname);
                  return -1;
            }
      }

      return 0;
}


void print_bin_struct_sizes(void)
{
      fprintf(stdout, "%ld %ld %ld %ld %ld %ld\n",
            (unsigned long int)sizeof(struct utilization_data),
            (unsigned long int)sizeof(struct adapter_utilization),
            (unsigned long int)sizeof(struct ioerr_data),
            (unsigned long int)sizeof(struct ioerr_cnt),
            (unsigned long int)sizeof(struct zfcpdd_dstat),
            (unsigned long int)sizeof(struct blkiomon_stat));
}


static int convert_long_optarg(long *tgt, char *option_str)
{
      if (!optarg) {
            fprintf(stderr, "%s: Error: Argument missing to"
                  " option %s\n", toolname, option_str);
            return -1;
      }
      *tgt = strtol(optarg, NULL, 0);
      if (errno) {
            fprintf(stderr, "%s: Error converting %s to"
                  " long: %s\n", toolname, optarg, strerror(errno));
            return -1;
      }

      return 0;
}


static int parse_params(int argc, char **argv, struct options *opts)
{
      int c;
      int error=0;
      int index;
        static struct option long_options[] = {
                { "version",         no_argument,       NULL, 'v'},
            { "help",            no_argument,       NULL, 'h'},
            { "binary-offsets",  no_argument,       NULL, 'e'},
                { "interval-length", required_argument, NULL, 'i'},
            { "msg-queue-name",  required_argument, NULL, 'Q'},
            { "msg-queue-id",    required_argument, NULL, 'q'},
            { "util-id",         required_argument, NULL, 'u'},
            { "ioerr-id",        required_argument, NULL, 'r'},
            { "blkiomon-id",     required_argument, NULL, 'b'},
            { "ziomon-zfcp-id",  required_argument, NULL, 'z'},
            { "verbose",         no_argument,       NULL, 'V'},
            { "size-limit",      required_argument, NULL, 'l'},
            { "enforce-version", required_argument, NULL, 'x'},
            { "output",          required_argument, NULL, 'o'},
            { "force",           no_argument,       NULL, 'f'},
                { 0,                 0,                 0,     0 }
      };

      if (argc <= 1) {
            print_help();
            return 1;
      }

      while ((c = getopt_long(argc, argv, "r:Q:q:u:b:z:i:l:o:x:Vhfev",
                        long_options, &index)) != EOF) {
            switch (c) {
            case 'V':
                  verbose++;
                  break;
            case 'Q':
                  if (!optarg) {
                        fprintf(stderr, "%s: Error:"
                              " Argument missing to option '-Q'\n",
                              toolname);
                        return -1;
                  }
                  opts->msg_q_path = optarg;
                  break;
            case 'q':
                  if (!optarg) {
                        fprintf(stderr, "%s: Error:"
                              " Argument missing to option '-q'\n",
                              toolname);
                        return -1;
                  }
                  opts->msg_q_id = atoi(optarg);
                  if (opts->msg_q_id < 0) {
                        fprintf(stderr, "%s: Error:"
                              " Parameter to option '-q' must be"
                              " greater than 0\n", toolname);
                        return -1;
                  }
                  break;
            case 'u':
                  if (convert_long_optarg(&opts->msg_id_utilization,
                                    "'-u'"))
                        return -1;
                  break;
            case 'r':
                  if (convert_long_optarg(&opts->msg_id_ioerr,
                                    "'-r"))
                        return -1;
                  break;
            case 'b':
                  if (convert_long_optarg(&opts->msg_id_blkiomon,
                                    "'-b'"))
                        return -1;
                  break;
            case 'z':
                  if (convert_long_optarg(&opts->msg_id_zfcpdd,
                                    "'-z'"))
                        return -1;
                  break;
            case 'h':
                  print_help();
                  return 1;
            case 'e':
                  print_bin_struct_sizes();
                  return 1;
            case 'f':
                  opts->force = 1;
                  break;
            case 'i':
                  if (!optarg) {
                        fprintf(stderr, "%s: Argument missing to"
                              " option '-i'\n", toolname);
                        return -1;
                  }
                  opts->interval_length = atoi(optarg);
                  if (opts->interval_length <= 0) {
                        fprintf(stderr, "%s: Interval"
                              " length must be >0\n", toolname);
                        return -1;
                  }
                  break;
            case 'o':
                  if (!optarg) {
                        fprintf(stderr, "%s: Argument missing to"
                              " option '-o'\n", toolname);
                        return -1;
                  }
                  if (opts->outfile_name) {
                        fprintf(stderr, "%s: Multiple instance of "
                              " option '-o'\n", toolname);
                        return -2;
                  }
                  opts->outfile_name = malloc(strlen(optarg)
                              + strlen(DACC_FILE_EXT_LOG) + 1);
                  if (!opts->outfile_name) {
                        fprintf(stderr, "%s: Memory allocation "
                              "error\n", toolname);
                        return -3;
                  }
                  opts->outfile_name_agg = malloc(strlen(optarg)
                              + strlen(DACC_FILE_EXT_AGG) + 1);
                  sprintf(opts->outfile_name, "%s" DACC_FILE_EXT_LOG,
                        optarg);
                  sprintf(opts->outfile_name_agg, "%s" DACC_FILE_EXT_AGG,
                        optarg);
                  break;
            case 'l':
                  if (!optarg) {
                        fprintf(stderr, "%s: Argument missing to"
                              " option '-o'\n", toolname);
                        return -1;
                  }
                  opts->size_limit = strtol(optarg, NULL, 0);
                  if (errno) {
                        fprintf(stderr, "%s: Error during conversion:"
                              " %s\n", toolname, strerror(errno));
                        return -1;
                  }
                  if (opts->size_limit < 1) {
                        fprintf(stderr, "%s: Size limit must be >=1.\n",
                              toolname);
                        return -1;
                  }
                  opts->size_limit *= 1024*1024;
                  break;
            case 'x':
                  if (!optarg) {
                        fprintf(stderr, "%s: Argument missing to"
                              " option '-x'\n", toolname);
                        return -1;
                  }
                  opts->version = strtol(optarg, NULL, 0);
                  if (errno) {
                        fprintf(stderr, "%s: Error during conversion:"
                              " %s\n", toolname, strerror(errno));
                        return -1;
                  }
                  if (opts->version < 2 || opts->version > 3) {
                        fprintf(stderr, "%s: Enforced version can only be"
                              "2 or 3.\n", toolname);
                        return -1;
                  }
                  break;
            case 'v':
                  print_version();
                  return 1;
            default:
                  fprintf(stderr, "Try '%s --help' for"
                        " more information.\n", toolname);
                  return -1;
            }
      }

      if (!opts->msg_q_path) {
            fprintf(stderr, "%s: No message queue path specified\n",
                        toolname);
            error++;
      }
      if (opts->msg_q_id < 0) {
            fprintf(stderr, "%s: No message queue"
                  " id specified\n", toolname);
            error++;
      }
      if (opts->msg_id_blkiomon == LONG_MIN) {
            fprintf(stderr, "%s: No id for blkiomon"
                  " messages specified\n", toolname);
            error++;
      }
      if (opts->msg_id_utilization == LONG_MIN) {
            fprintf(stderr, "%s: No id for"
                  " utilizaton messages specified\n", toolname);
            error++;
      }
      if (opts->msg_id_ioerr == LONG_MIN) {
            fprintf(stderr, "%s: No id for"
                  " ioerr messages specified\n", toolname);
            error++;
      }
      if (opts->msg_id_zfcpdd == LONG_MIN) {
            fprintf(stderr, "%s: No id for"
                  " ziomon_zfcpdd messages specified\n", toolname);
            error++;
      }
      if (opts->interval_length < 0) {
            fprintf(stderr, "%s: No interval length"
                  " specified\n", toolname);
            error++;
      }
      if (!opts->outfile_name) {
            fprintf(stderr, "%s: No filename for"
                  " output specified\n", toolname);
            error++;
      }
      if (error)
            return -1;

      if (check_msg_ids(opts))
            return -1;

      opts->outfile = fopen(opts->outfile_name, "w+");
      if (!opts->outfile) {
            fprintf(stderr, "%s: Could not open output"
                  " file: %s\n", toolname, strerror(errno));
            return -1;
      }

      if (setup_msg_q(opts))
            return -1;

      verbose_msg("interval length      : %d\n", opts->interval_length);
      verbose_msg("force                : %d\n", opts->force);
      verbose_msg("message queue path   : %s\n", opts->msg_q_path);
      verbose_msg("message queue id     : %d\n", opts->msg_q_id);
      verbose_msg("message queue        : %d\n", opts->msg_q);
      verbose_msg("msg id utilization   : %ld\n", opts->msg_id_utilization);
      verbose_msg("msg id ioerr         : %ld\n", opts->msg_id_ioerr);
      verbose_msg("msg id blkiomon      : %ld\n", opts->msg_id_blkiomon);
      verbose_msg("msg id ziomon_zfcpdd : %ld\n", opts->msg_id_zfcpdd);
      verbose_msg("outfile name         : %s\n", opts->outfile_name);
      if (opts->size_limit == LONG_MAX)
            verbose_msg("size limit           : no limit\n");
      else
            verbose_msg("size limit           : %ld Bytes\n", opts->size_limit);

      return 0;
}


static void void_handler(int sig)
{
      verbose_msg("interrupted by signal %u\n", sig);
      keep_running = 0;
}


static void print_timestamp(struct tm *my_tm, const char *type, __u32 length,
                      struct timeval *t)
{
      verbose_msg("%02d:%02d:%02d.%06ld: received %s"
                " message of %u bytes\n", my_tm->tm_hour,
                my_tm->tm_min, my_tm->tm_sec, t->tv_usec, type, length);
}


static int handle_msg(struct message *msg, struct options *opts)
{
      struct message **msgs;
      int count;
      int rc = 0;
      struct timeval t;
      struct tm *my_tm = NULL;

      if (verbose) {
            gettimeofday(&t, NULL);
            my_tm = localtime(&t.tv_sec);
      }

      if ((long)msg->type == opts->msg_id_utilization)
            print_timestamp(my_tm, "utilization", msg->length, &t);
      else if ((long)msg->type == opts->msg_id_ioerr)
            print_timestamp(my_tm, "ioerr", msg->length, &t);
      else if ((long)msg->type == opts->msg_id_blkiomon)
            print_timestamp(my_tm, "blkiomon", msg->length, &t);
      else if ((long)msg->type == opts->msg_id_zfcpdd)
            print_timestamp(my_tm, "zfcpdd", msg->length, &t);
      else {
            fprintf(stderr, "%s: Received message of "
                        "unrecognized type %d, length %d bytes, "
                        "discarding\n", toolname, msg->type, msg->length);
            return 1;
      }

      if (add_msg(opts->outfile, msg, &opts->f_hdr, &msgs, &count)) {
            fprintf(stderr, "%s: Error while writing"
                  " message\n", toolname);
            rc = -1;
      } else
            verbose_msg("message written\n");
      if (count) {
            if (add_to_aggregated(msgs, count, opts)) {
                  fprintf(stderr, "%s: Failed to aggregate"
                        " %d messages\n", toolname, count);
                  rc = -1;
            }
      }

      return rc;
}


int main(int argc, char **argv)
{
      int rc = 0;
      struct options opts;
      int len;
      int data_sz = 1024;
      long *data = malloc(data_sz + sizeof(long));
      int tmperr;
      struct message msg;

      verbose = 0;

      signal(SIGALRM, void_handler);
      signal(SIGINT,  void_handler);
      signal(SIGTERM, void_handler);
      signal(SIGQUIT, void_handler);

      init_opts(&opts);

      if (parse_params(argc, argv, &opts))
            goto out;

      /* first write to file, init section for cumulatives */
      verbose_msg("init file...\n");
      opts.f_hdr.msgid_utilization = opts.msg_id_utilization;
      opts.f_hdr.msgid_ioerr = opts.msg_id_ioerr;
      opts.f_hdr.msgid_blkiomon = opts.msg_id_blkiomon;
      opts.f_hdr.msgid_zfcpdd = opts.msg_id_zfcpdd;
      opts.f_hdr.size_limit = opts.size_limit;
      opts.f_hdr.interval_length = opts.interval_length;
      if (init_file(opts.outfile, &opts.f_hdr, opts.version))
            goto out;

      verbose_msg("wait for messages...\n");
      do {
            len = msgrcv(opts.msg_q, data, data_sz, 0, 0);
            if (!keep_running)
                  break;
            if (len < 0) {
                  tmperr = errno;
                  if (tmperr == E2BIG) {
                        data_sz *= 2;
                        data = realloc(data, data_sz + sizeof(long));
                        verbose_msg("message buffer too small,"
                                  " increasing to %d\n", data_sz);
                        continue;
                  }
                  fprintf(stderr, "%s: Error receiving"
                        " message: %s\n", toolname, strerror(errno));
                  verbose_msg("msgrcv() returned error %d\n", tmperr);
                  break;
            }
            msg.length = len;
            msg.data = data + 1;
            msg.type = *data;
            handle_msg(&msg, &opts);

      } while (keep_running);

out:
      deinit_opts(&opts);
      free(data);

      return rc;
}




Generated by  Doxygen 1.6.0   Back to index