mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
659 lines
16 KiB
C
659 lines
16 KiB
C
/*
|
|
* FCP adapter trace utility
|
|
*
|
|
* Central message collection tool
|
|
*
|
|
* Copyright IBM Corp. 2008, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <limits.h>
|
|
#include <linux/types.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/msg.h>
|
|
#include <sys/msg.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/zt_common.h"
|
|
|
|
#include "ziomon_dacc.h"
|
|
#include "ziomon_msg_tools.h"
|
|
#include "ziomon_tools.h"
|
|
#include "ziomon_util.h"
|
|
#include "ziomon_zfcpdd.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, 2017\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;
|
|
}
|
|
|
|
|
|
|