Files
hdf5/hl/tools/h5watch/h5watch.c
Jordan Henderson 254388494a Update Tools library to be better compatible with VOL connectors
Modify h5repack to integrate with VOL connectors

Update tools library to accomodate VOL connectors

Update logic in h5tools_fopen for VOL connectors

Add command-line options to h5repack for specifying in/out VOL
connectors

Implement h5tools_set_vol_fapl

Fix library shutdown issue

Integrate ROS3 and HDFS VFDs into new h5tools_get_fapl() scheme

Avoid H5Ocopy in h5repack when using different VOL connectors

Update h5tools_test_utils.c for ROS3 and HDFS integration
2020-05-20 09:31:56 -05:00

981 lines
34 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* Copyright by the Board of Trustees of the University of Illinois. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "h5tools.h"
#include "h5tools_dump.h"
#include "H5LDprivate.h"
/*
* Note: This tool used private routine
*/
#define PROGRAMNAME "h5watch" /* Name of tool */
#define FIELD_SEP "," /* nested field separator */
#define DEFAULT_RETRY 50 /* number of times to try opening the file */
/*
* Note:(see comments in hl/src/H5LDprivate.h)
* This tool uses private routines H5LD_construct_vector()and H5LD_clean_vector()
* This tool uses H5LD_memb_t data structure declared in H5LDprivate.h
*/
const char *progname = "h5watch"; /* tool name */
static char *g_list_of_fields = NULL; /* command line input for "list_of_fields" */
static char *g_dup_fields = NULL; /* copy of "list_of_fields" */
static H5LD_memb_t **g_listv = NULL; /* vector info for "list_of_fields" */
static hbool_t g_monitor_size_only = FALSE; /* monitor changes in dataset dimension sizes */
static unsigned g_polling_interval = 1; /* polling interval to check appended data */
static hbool_t g_label = FALSE; /* label compound values */
static int g_display_width = 80; /* output width in characters */
static hbool_t g_simple_output = FALSE; /* make output more machine-readable */
static unsigned g_retry = DEFAULT_RETRY; /* # of times to try opening the file if somehow file is unstable */
static hbool_t g_display_hex = FALSE; /* display data in hexadecimal format : LATER */
static hbool_t g_user_interrupt = FALSE; /* Flag to indicate that user interrupted execution */
static herr_t doprint(hid_t did, hsize_t *start, hsize_t *block, int rank);
static herr_t slicendump(hid_t did, hsize_t *prev_dims, hsize_t *cur_dims,
hsize_t *start, hsize_t *block, int rank, int subrank);
static herr_t monitor_dataset(hid_t fid, char *dsetname);
static herr_t process_cmpd_fields(hid_t fid, char *dsetname);
static herr_t check_dataset(hid_t fid, char *dsetname);
static void leave(int ret);
static void usage(const char *prog);
static void parse_command_line(int argc, const char *argv[]);
/*
* Command-line options: The user can only specify long-named parameters.
* The long-named ones can be partially spelled. When
* adding more, make sure that they don't clash with each other.
*/
static const char *s_opts ="?";
static struct long_options l_opts[] = {
{ "help", no_arg, 'h' },
{ "hel", no_arg, 'h' },
{ "dim", no_arg, 'd' },
{ "di", no_arg, 'd' },
{ "label", no_arg, 'l' },
{ "labe", no_arg, 'l' },
{ "lab", no_arg, 'l' },
{ "la", no_arg, 'l' },
{ "simple", no_arg, 'S' },
{ "simpl", no_arg, 'S' },
{ "simp", no_arg, 'S' },
{ "sim", no_arg, 'S' },
{ "si", no_arg, 'S' },
{ "hexdump", no_arg, 'x' },
{ "hexdum", no_arg, 'x' },
{ "hexdu", no_arg, 'x' },
{ "hexd", no_arg, 'x' },
{ "hex", no_arg, 'x' },
{ "width", require_arg, 'w' },
{ "widt", require_arg, 'w' },
{ "wid", require_arg, 'w' },
{ "wi", require_arg, 'w' },
{ "polling", require_arg, 'p' },
{ "pollin", require_arg, 'p' },
{ "polli", require_arg, 'p' },
{ "poll", require_arg, 'p' },
{ "pol", require_arg, 'p' },
{ "po", require_arg, 'p' },
{ "fields", require_arg, 'f' },
{ "field", require_arg, 'f' },
{ "fiel", require_arg, 'f' },
{ "fie", require_arg, 'f' },
{ "fi", require_arg, 'f' },
{ "version", no_arg, 'V' },
{ "versio", no_arg, 'V' },
{ "versi", no_arg, 'V' },
{ "vers", no_arg, 'V' },
{ "ver", no_arg, 'V' },
{ "ve", no_arg, 'V' },
{ NULL, 0, '\0' }
};
/*-------------------------------------------------------------------------
* Function: doprint()
*
* Purpose: Prepare to print the dataset's appended data.
* Call the tools library routine h5tools_dump_dset() to do the printing.
* (This routine is mostly copied from dump_dataset_values() in tools/h5ls/h5ls.c
* and modified accordingly).
*
* Return: 0 on success; negative on failure
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
doprint(hid_t did, hsize_t *start, hsize_t *block, int rank)
{
h5tools_context_t ctx; /* print context */
h5tool_format_t info; /* Format info for the tools library */
static char fmt_double[16], fmt_float[16]; /* Format info */
struct subset_t subset; /* Subsetting info */
hsize_t ss_start[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_stride[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_block[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_count[H5S_MAX_RANK]; /* Info for hyperslab */
int i; /* Local index variable */
herr_t ret_value = SUCCEED; /* Return value */
/* Subsetting information for the tools library printing routines */
subset.start.data = ss_start;
subset.stride.data = ss_stride;
subset.block.data = ss_block;
subset.count.data = ss_count;
/* Initialize subsetting information */
for(i = 0; i < rank; i++) {
subset.stride.data[i] = 1;
subset.count.data[i] = 1;
subset.start.data[i] = start[i];
subset.block.data[i] = block[i];
} /* end for */
HDmemset(&ctx, 0, sizeof(ctx));
ctx.sset = &subset;
/* Set to all default values and then override */
HDmemset(&info, 0, sizeof info);
if(g_simple_output) {
info.idx_fmt = "";
info.line_ncols = 65535; /*something big*/
info.line_per_line = 1;
info.line_multi_new = 0;
info.line_pre = " ";
info.line_cont = " ";
info.arr_pre = "";
info.arr_suf = "";
info.arr_sep = " ";
info.cmpd_pre = "";
info.cmpd_suf = "";
info.cmpd_sep = " ";
/* The "fields" selected by the user */
info.cmpd_listv = (const struct H5LD_memb_t * const *)g_listv;
if(g_label)
info.cmpd_name = "%s=";
info.elmt_suf1 = " ";
info.str_locale = ESCAPE_HTML;
} else {
info.idx_fmt = "(%s)";
if(!g_display_width) {
info.line_ncols = 65535;
info.line_per_line = 1;
} /* end if */
else
info.line_ncols = (unsigned)g_display_width;
info.line_multi_new = 1;
/* The "fields" selected by the user */
info.cmpd_listv = (const struct H5LD_memb_t * const *)g_listv;
if(g_label)
info.cmpd_name = "%s=";
info.line_pre = " %s ";
info.line_cont = " %s ";
info.str_repeat = 8;
} /* end else */
/* Floating point types should display full precision */
sprintf(fmt_float, "%%1.%dg", FLT_DIG);
info.fmt_float = fmt_float;
sprintf(fmt_double, "%%1.%dg", DBL_DIG);
info.fmt_double = fmt_double;
info.dset_format = "DSET-%s ";
info.dset_hidefileno = 0;
info.obj_format = "-%lu:%" PRIuHADDR;
info.obj_hidefileno = 0;
info.dset_blockformat_pre = "%sBlk%lu: ";
info.dset_ptformat_pre = "%sPt%lu: ";
info.line_indent = "";
if(g_display_hex) {
/* Print all data in hexadecimal format if the `-x' or `--hexdump'
* command line switch was given. */
info.raw = TRUE;
} /* end if */
/* Print the values. */
if((ret_value = h5tools_dump_dset(stdout, &info, &ctx, did)) < 0)
error_msg("unable to print data\n");
HDfprintf(stdout, "\n");
return ret_value;
} /* end doprint() */
/*-------------------------------------------------------------------------
* Function: slicendump
*
* Purpose: To dump the slice for each dimension
* For example: prev_dims[2] = {5, 4}; cur_dims[2] = {7, 8}
* This routine will dump data as follows:
* {0, 3} to {0, 7} (1x4 elements)
* {1, 3} to {0, 7} (1x4 elements)
* {2, 3} to {0, 7} (1x4 elements)
* {3, 3} to {0, 7} (1x4 elements)
* {4, 3} to {0, 7} (1x4 elements)
* {5, 0} to {6, 7} (2x8 elements)
*
* Return: Non-negative on success
* Negative on failure
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
slicendump(hid_t did, hsize_t *prev_dims, hsize_t *cur_dims, hsize_t *start, hsize_t *block, int rank, int subrank)
{
int i; /* Local index variable */
int ind; /* Index for the current rank */
herr_t ret_value = SUCCEED; /* Return value */
ind = rank - subrank;
if((subrank - 1) > 0) {
/* continue onto the next dimension */
for (i = 0; i < (hssize_t)MIN(prev_dims[ind], cur_dims[ind]); i++){
start[ind] = (hsize_t)i;
if((ret_value = slicendump(did, prev_dims, cur_dims, start, block, rank, subrank-1)) < 0)
goto done;
} /* end for */
} /* end if */
/* this dimension remains the same or shrinking */
if(cur_dims[ind] <= prev_dims[ind])
goto done;
/* select first the slice for the faster changing dimension */
/* select later the whole slice for the slower changing dimension */
start[ind] = prev_dims[ind];
block[ind] = cur_dims[ind] - prev_dims[ind];
for(i = ind + 1; i < rank; i++){
start[i] = 0;
block[i] = cur_dims[i];
} /* end for */
/* Print the appended data */
ret_value = doprint(did, start, block, rank);
done:
return ret_value;
} /* end slicendump() */
/*-------------------------------------------------------------------------
* Function: monitor_dataset
*
* Purpose: To poll a dataset periodically for changes in dimension sizes.
* For dataset with unchanged and/or decreased dimension sizes:
* it just prints the dimension size changes
* For dataset with increase in at least one of its dimension sizes:
* it will print the new appended data to the dataset
*
* Return: Non-negative on success: dataset can be monitored
* Negative on failure: dataset cannot be monitored
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
monitor_dataset(hid_t fid, char *dsetname)
{
hid_t did; /* dataset id */
hid_t sid; /* dataspace id */
int ndims; /* # of dimensions in the dataspace */
int i, u; /* local index variable */
hsize_t prev_dims[H5S_MAX_RANK]; /* current dataspace dimensions */
hsize_t cur_dims[H5S_MAX_RANK]; /* previous dataspace dimensions */
herr_t ret_value = SUCCEED; /* return value */
HDfprintf(stdout, "Monitoring dataset %s...\n", dsetname);
/* Open the dataset for minitoring */
if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
error_msg("error in opening dataset \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
if((sid = H5Dget_space(did)) < 0) {
error_msg("error in getting dataspace id for dataset \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Get the dataset's dimension sizes */
if((ndims = H5Sget_simple_extent_dims(sid, prev_dims, NULL)) < 0) {
error_msg("unable to get dimensions sizes for \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
HDfflush(stdout);
/* Loop until an error occurs or the user interrupts execution */
while(!g_user_interrupt) {
/* Refreshes the dataset */
if(H5Drefresh(did) < 0) {
ret_value = FAIL;
goto done;
}
/* Get the dataset's current dimension sizes */
if(H5LDget_dset_dims(did, cur_dims) < 0) {
error_msg("unable to get dimension sizes for \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Check the dimension sizes */
for(i = 0; i < ndims; i++)
if(cur_dims[i] != prev_dims[i])
break;
/* at least one dimension has changed */
if(i != ndims) {
/* Printing changes in dimension sizes */
for(u = 0; u < ndims; u++) {
HDfprintf(stdout, "dimension %u: %Hu->%Hu", (unsigned)u, prev_dims[u], cur_dims[u]);
if(cur_dims[u] > prev_dims[u])
HDfprintf(stdout, " (increases)\n");
else if(cur_dims[u] < prev_dims[u])
HDfprintf(stdout, " (decreases)\n");
else
HDfprintf(stdout, " (unchanged)\n");
}
/* Printing elements appended to the dataset if there is */
if(!g_monitor_size_only) {
/* See if at least one dimension size has increased */
for(u = 0; u < ndims; u++) {
int j;
hsize_t start[H5S_MAX_RANK];
hsize_t block[H5S_MAX_RANK];
/* Print the new appended data to the dataset */
if(cur_dims[u] > prev_dims[u]) {
HDfprintf(stdout, " Data:\n");
for(j = 0; j < ndims; j++) {
start[j] = 0;
block[j] = 1;
}
if((ret_value = slicendump(did, prev_dims, cur_dims, start, block, ndims, ndims)) < 0)
goto done;
break;
}
} /* end for */
}
HDfflush(stdout);
}
/* Save the current dimension sizes */
HDmemcpy(prev_dims, cur_dims, (size_t)ndims * sizeof(hsize_t));
/* Sleep before next monitor */
HDsleep(g_polling_interval);
} /* end while */
HDfflush(stdout);
done:
/* Closing */
H5E_BEGIN_TRY
H5Dclose(did);
H5E_END_TRY
return(ret_value);
} /* monitor_dataset() */
/*-------------------------------------------------------------------------
* Function: process_cmpd_fields
*
* Purpose: To check whether the fields selected in "g_list_of_fields"
* are valid fields associated with the dataset.
*
* Return: 0 on success; negative on failure
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
process_cmpd_fields(hid_t fid, char *dsetname)
{
hid_t did=-1; /* dataset id */
hid_t dtid=-1, tid=-1; /* dataset's data type id */
size_t len; /* number of comma-separated fields in "g_list_of_fields" */
herr_t ret_value = SUCCEED; /* Return value */
HDassert(g_list_of_fields && *g_list_of_fields);
/* Open the dataset */
if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
error_msg("error in opening dataset \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Get the dataset's datatype */
if(((dtid = H5Dget_type(did)) < 0) || (tid = H5Tget_native_type(dtid, H5T_DIR_DEFAULT)) < 0) {
error_msg("error in getting dataset's datatype\n");
ret_value = FAIL;
goto done;
}
/* Check to make sure that the dataset's datatype is compound type */
if(H5Tget_class(dtid) != H5T_COMPOUND) {
error_msg("dataset should be compound type for <list_of_fields>\n");
ret_value = FAIL;
goto done;
}
/* Make a copy of "g_list_of_fields" */
if((g_dup_fields = HDstrdup(g_list_of_fields)) == NULL) {
error_msg("error in duplicating g_list_of_fields\n");
ret_value = FAIL;
goto done;
}
/* Estimate the number of comma-separated fields in "g_list of_fields" */
len = HDstrlen(g_list_of_fields)/2 + 2;
/* Allocate memory for a list vector of H5LD_memb_t structures to store "g_list_of_fields" info */
if((g_listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))) == NULL) {
error_msg("error in allocating memory for H5LD_memb_t\n");
ret_value = FAIL;
goto done;
}
/* Process and store info for "g_listv" */
if(H5LD_construct_vector(g_dup_fields, g_listv, tid) < 0) {
error_msg("error in processing <list_of_fields>\n");
ret_value = FAIL;
goto done;
}
/* Will free memory for g_listv and g_dup_fields when exiting from h5watch */
done:
/* Closing */
H5E_BEGIN_TRY
H5Tclose(dtid);
H5Tclose(tid);
H5Dclose(did);
H5E_END_TRY
return(ret_value);
} /* process_cmpd_fields() */
/*-------------------------------------------------------------------------
* Function: check_dataset
*
* Purpose: To check whether a dataset can be monitored:
* A chunked dataset with unlimited or max. dimension setting
*
* Return: Non-negative on success: dataset can be monitored
* Negative on failure: dataset cannot be monitored
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
check_dataset(hid_t fid, char *dsetname)
{
hid_t did=-1; /* Dataset id */
hid_t dcp=-1; /* Dataset creation property */
hid_t sid=-1; /* Dataset's dataspace id */
int ndims; /* # of dimensions in the dataspace */
unsigned u; /* Local index variable */
hsize_t cur_dims[H5S_MAX_RANK]; /* size of dataspace dimensions */
hsize_t max_dims[H5S_MAX_RANK]; /* maximum size of dataspace dimensions */
hbool_t unlim_max_dims = FALSE; /* whether dataset has unlimited or max. dimension setting */
void *edata;
H5E_auto2_t func;
H5D_layout_t layout;
herr_t ret_value = SUCCEED; /* Return value */
/* Disable error reporting */
H5Eget_auto2(H5E_DEFAULT, &func, &edata);
H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
/* Open the dataset */
if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
error_msg("unable to open dataset \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Get dataset's creation property list */
if((dcp = H5Dget_create_plist(did)) < 0) {
error_msg("unable to get dataset's creation property list \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Query dataset's layout; the layout should be chunked or virtual */
if((layout = H5Pget_layout(dcp)) < 0) {
error_msg("unable to get dataset layout \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
if(layout != H5D_CHUNKED && layout != H5D_VIRTUAL) {
error_msg("\"%s\" should be a chunked or virtual dataset\n", dsetname);
ret_value = FAIL;
goto done;
}
HDmemset(cur_dims, 0, sizeof cur_dims);
HDmemset(max_dims, 0, sizeof max_dims);
/* Get dataset's dataspace */
if((sid = H5Dget_space(did)) < 0) {
error_msg("can't get dataset's dataspace\"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Get dimension size of dataset's dataspace */
if((ndims = H5Sget_simple_extent_dims(sid, cur_dims, max_dims)) < 0) {
error_msg("can't get dataspace dimensions for dataset \"%s\"\n", dsetname);
ret_value = FAIL;
goto done;
}
/* Check whether dataset has unlimited dimension or max. dimension setting */
for(u = 0; u < (unsigned)ndims; u++)
if(max_dims[u] == H5S_UNLIMITED || cur_dims[u] != max_dims[u]) {
unlim_max_dims = TRUE;
break;
}
if(!unlim_max_dims) {
error_msg("\"%s\" should have unlimited or max. dimension setting\n", dsetname);
ret_value = FAIL;
}
done:
H5Eset_auto2(H5E_DEFAULT, func, edata);
/* Closing */
H5E_BEGIN_TRY
H5Sclose(sid);
H5Pclose(dcp);
H5Dclose(did);
H5E_END_TRY
return(ret_value);
} /* check_dataset() */
/*-------------------------------------------------------------------------
* Function: leave
*
* Purpose: Close the H5 Tools library and exit
*
* Return: Does not return
*
* Programmer: Vailin Choi; August 2010
*
*
*-------------------------------------------------------------------------
*/
static void
leave(int ret)
{
h5tools_close();
exit(ret);
}
/*-------------------------------------------------------------------------
* Function: usage
*
* Purpose: Print the usage message about h5watch (only long options)
*
* Return: void
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static void
usage(const char *prog)
{
HDfflush(stdout);
HDfprintf(stdout, "Usage: %s [OPTIONS] [OBJECT]\n", prog);
HDfprintf(stdout, "\n");
HDfprintf(stdout, " OPTIONS\n");
HDfprintf(stdout, " --help Print a usage message and exit.\n");
HDfprintf(stdout, " --version Print version number and exit.\n");
HDfprintf(stdout, " --label Label members of compound typed dataset.\n");
HDfprintf(stdout, " --simple Use a machine-readable output format.\n");
HDfprintf(stdout, " --dim Monitor changes in size of dataset dimensions only.\n");
HDfprintf(stdout, " --width=N Set the number of columns to N for output.\n");
HDfprintf(stdout, " A value of 0 sets the number of columns to the\n");
HDfprintf(stdout, " maximum (65535). The default width is 80 columns.\n");
HDfprintf(stdout, " --polling=N Set the polling interval to N (in seconds) when the\n");
HDfprintf(stdout, " dataset will be checked for appended data. The default\n");
HDfprintf(stdout, " polling interval is 1.\n");
HDfprintf(stdout, " --fields=<list_of_fields>\n");
HDfprintf(stdout, " Display data for the fields specified in <list_of_fields>\n");
HDfprintf(stdout, " for a compound data type. <list_of_fields> can be\n");
HDfprintf(stdout, " specified as follows:\n");
HDfprintf(stdout, " 1) A comma-separated list of field names in a\n");
HDfprintf(stdout, " compound data type. \",\" is the separator\n");
HDfprintf(stdout, " for field names while \".\" is the separator\n");
HDfprintf(stdout, " for a nested field.\n");
HDfprintf(stdout, " 2) A single field name in a compound data type.\n");
HDfprintf(stdout, " Can use this option multiple times.\n");
HDfprintf(stdout, " Note that backslash is the escape character to avoid\n");
HDfprintf(stdout, " characters in field names that conflict with the tool's\n");
HDfprintf(stdout, " separators.\n");
HDfprintf(stdout, "\n");
HDfprintf(stdout, " OBJECT is specified as [<filename>/<path_to_dataset>/<dsetname>]\n");
HDfprintf(stdout, " <filename> Name of the HDF5 file. It may be preceded by path\n");
HDfprintf(stdout, " separated by slashes to the specified HDF5 file.\n");
HDfprintf(stdout, " <path_to_dataset> Path separated by slashes to the specified dataset\n");
HDfprintf(stdout, " <dsetname> Name of the dataset\n");
HDfprintf(stdout, "\n");
HDfprintf(stdout, " User can end the h5watch process by ctrl-C (SIGINT) or kill the process (SIGTERM).\n");
} /* usage() */
/*-------------------------------------------------------------------------
* Function: parse_command_line
*
* Purpose: Parse the command line for h5watch (take only long options)
*
* Return: Success: Set the corresponding command flags and return void
* Failure: Exits program with EXIT_FAILURE value.
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
static void
parse_command_line(int argc, const char *argv[])
{
int opt; /* Command line option */
int tmp;
/* no arguments */
if (argc == 1) {
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
/* parse command line options */
while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
switch ((char)opt) {
case '?':
case 'h': /* --help */
usage(h5tools_getprogname());
leave(EXIT_SUCCESS);
break;
case 'V': /* --version */
print_version(progname);
leave(EXIT_SUCCESS);
break;
case 'w': /* --width=N */
g_display_width = (int)HDstrtol(opt_arg, NULL, 0);
if(g_display_width < 0) {
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
break;
case 'd': /* --dim */
g_monitor_size_only = TRUE;
break;
case 'S': /* --simple */
g_simple_output = TRUE;
break;
case 'l': /* --label */
g_label = TRUE;
break;
case 'p': /* --polling=N */
/* g_polling_interval = HDstrtod(opt_arg, NULL); */
if((tmp = (int)HDstrtol(opt_arg, NULL, 10)) <= 0) {
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
g_polling_interval = (unsigned)tmp;
break;
case 'f': /* --fields=<list_of_fields> */
if(g_list_of_fields == NULL) {
if((g_list_of_fields = HDstrdup(opt_arg)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n",
__FILE__, __LINE__);
leave(EXIT_FAILURE);
}
} else {
char *str;
if((str = HDstrdup(opt_arg)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n",
__FILE__, __LINE__);
leave(EXIT_FAILURE);
}
if((g_list_of_fields = (char *)HDrealloc(g_list_of_fields, HDstrlen(g_list_of_fields) + HDstrlen(str) + 2)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n",
__FILE__, __LINE__);
leave(EXIT_FAILURE);
}
HDstrcat(g_list_of_fields, FIELD_SEP);
HDstrcat(g_list_of_fields, str);
}
break;
default:
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
}
/* check for object to be processed */
if (argc <= opt_ind) {
error_msg("missing dataset name\n");
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
} /* parse_command_line() */
/*-------------------------------------------------------------------------
* Function: catch_signal
*
* Purpose: The signal handler to catch the signals:
* SIGTERM and SIGINT and set flag to get out of the main loop
*
* Return: No return
*
* Programmer: Vailin Choi; November 2014
*
*-------------------------------------------------------------------------
*/
static void catch_signal(int H5_ATTR_UNUSED signo)
{
/* Set the flag to get out of the main loop */
g_user_interrupt = TRUE;
} /* catch_signal() */
/*-------------------------------------------------------------------------
* Function: main
*
* Purpose: h5watch
*
* Return: Success: 0
* Failure: 1
*
* Programmer: Vailin Choi; August 2010
*
*-------------------------------------------------------------------------
*/
int
main(int argc, const char *argv[])
{
char drivername[50]; /* VFD name */
char *fname = NULL; /* File name */
char *dname = NULL; /* Dataset name */
void *edata; /* Error reporting */
void *tools_edata; /* Error reporting */
H5E_auto2_t func; /* Error reporting */
H5E_auto2_t tools_func; /* Error reporting */
char *x; /* Temporary string pointer */
hid_t fid = -1; /* File ID */
hid_t fapl = -1; /* File access property list */
/* Set up tool name and exit status */
h5tools_setprogname(PROGRAMNAME);
h5tools_setstatus(EXIT_SUCCESS);
/* Disable error reporting */
H5Eget_auto2(H5E_DEFAULT, &func, &edata);
H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
/* Initialize h5tools lib */
h5tools_init();
/* Disable tools error reporting */
H5Eget_auto2(H5tools_ERR_STACK_g, &tools_func, &tools_edata);
H5Eset_auto2(H5tools_ERR_STACK_g, NULL, NULL);
/* To exit from h5watch for SIGTERM signal */
if(HDsignal(SIGTERM, catch_signal) == SIG_ERR) {
error_msg("An error occurred while setting a signal handler.\n");
leave(EXIT_FAILURE);
}
/* To exit from h5watch for SIGINT signal */
if(HDsignal(SIGINT, catch_signal) == SIG_ERR) {
error_msg("An error occurred while setting a signal handler.\n");
leave(EXIT_FAILURE);
}
/* parse command line options */
parse_command_line(argc, argv);
if(argc <= opt_ind) {
error_msg("missing dataset name\n");
usage(h5tools_getprogname());
leave(EXIT_FAILURE);
}
/* Mostly copied from tools/h5ls coding & modified accordingly */
/*
* [OBJECT] is specified as
* [<filename>/<path_to_dataset>/<dsetname>]
*
* Example: ../dir1/foo/bar/dset
* \_________/\______/
* file obj
*
* The dichotomy is determined by calling H5Fopen() repeatedly until it
* succeeds. The first call uses the entire name and each subsequent call
* chops off the last component. If we reach the beginning of the name
* then there must have been something wrong with the file (perhaps it
* doesn't exist).
*/
if((fname = HDstrdup(argv[opt_ind])) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n",
__FILE__, __LINE__);
h5tools_setstatus(EXIT_FAILURE);
}
/* Create a copy of file access property list */
if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
return -1;
/* Set to use the latest library format */
if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
return -1;
do {
while(fname && *fname) {
fid = h5tools_fopen(fname, H5F_ACC_RDONLY|H5F_ACC_SWMR_READ, fapl, FALSE, drivername, sizeof drivername);
if(fid >= 0) {
HDfprintf(stdout, "Opened \"%s\" with %s driver.\n", fname, drivername);
break; /*success*/
} /* end if */
/* Shorten the file name; lengthen the object name */
x = dname;
dname = HDstrrchr(fname, '/');
if(x)
*x = '/';
if(!dname)
break;
*dname = '\0';
} /* end while */
/* Try opening the file again if somehow unstable */
} while(g_retry-- > 0 && fid == FAIL);
if(fid < 0) {
error_msg("unable to open file \"%s\"\n", fname);
if(fname) HDfree(fname);
if(fapl >= 0) H5Pclose(fapl);
leave(EXIT_FAILURE);
}
if(!dname) {
error_msg("no dataset specified\n");
h5tools_setstatus(EXIT_FAILURE);
} else {
*dname = '/';
x = dname;
if((dname = HDstrdup(dname)) == NULL) {
error_msg("memory allocation failed (file %s:line %d)\n",
__FILE__, __LINE__);
h5tools_setstatus(EXIT_FAILURE);
} else {
*x = '\0';
/* Validate dataset */
if(check_dataset(fid, dname) < 0)
h5tools_setstatus(EXIT_FAILURE);
/* Validate input "fields" */
else if(g_list_of_fields && *g_list_of_fields)
if(process_cmpd_fields(fid, dname) < 0)
h5tools_setstatus(EXIT_FAILURE);
}
}
/* If everything is fine, start monitoring the datset */
if(h5tools_getstatus() != EXIT_FAILURE)
if(monitor_dataset(fid, dname) < 0)
h5tools_setstatus(EXIT_FAILURE);
/* Free spaces */
if(fname) HDfree(fname);
if(dname) HDfree(dname);
if(g_list_of_fields) HDfree(g_list_of_fields);
if(g_listv) {
H5LD_clean_vector(g_listv);
HDfree(g_listv);
}
if(g_dup_fields) HDfree(g_dup_fields);
/* Close the file access property list */
if(fapl >= 0 && H5Pclose(fapl) < 0) {
error_msg("unable to close file access property list\n");
h5tools_setstatus(EXIT_FAILURE);
}
/* Close the file */
if(H5Fclose(fid) < 0) {
error_msg("unable to close file\n");
h5tools_setstatus(EXIT_FAILURE);
}
H5Eset_auto2(H5E_DEFAULT, func, edata);
H5Eset_auto2(H5tools_ERR_STACK_g, tools_func, tools_edata);
/* exit */
leave(h5tools_getstatus());
} /* main() */