/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 = ⊂ /* 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:"H5_PRINTF_HADDR_FMT; 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 \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 \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=\n"); HDfprintf(stdout, " Display data for the fields specified in \n"); HDfprintf(stdout, " for a compound data type. 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 [//]\n"); HDfprintf(stdout, " 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 separated by slashes to the specified dataset\n"); HDfprintf(stdout, " 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= */ 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 */ H5E_auto2_t 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(); /* 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 * [//] * * 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, NULL, 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); /* exit */ leave(h5tools_getstatus()); } /* main() */