/****************************************************************************
* *
* COPYRIGHT (c) 1990 - 2004 *
* This Software Provided *
* By *
* Robin's Nest Software Inc. *
* *
* Permission to use, copy, modify, distribute and sell this software and *
* its documentation for any purpose and without fee is hereby granted, *
* provided that the above copyright notice appear in all copies and that *
* both that copyright notice and this permission notice appear in the *
* supporting documentation, and that the name of the author not be used *
* in advertising or publicity pertaining to distribution of the software *
* without specific, written prior permission. *
* *
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, *
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN *
* NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL *
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR *
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS *
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF *
* THIS SOFTWARE. *
* *
****************************************************************************/
/*
* Module: dtgen.c
* Author: Robin T. Miller
* Date: September 8, 1993
*
* Description:
* Generic test functions for the 'dt' program.
*
* Modification History:
*
* June 23rd, 2004 by Robin Miller.
* Added support for triggers on corruption.
* Allow non-modulo record sizes for regular files.
*
* February 27th, 2004 by Robin Miller.
* In open_file() pre-format error string for Hazard printing.
*
* November 17th, 2003 by Robin Miller.
* Breakup output to stdout or stderr, rather than writing
* all output to stderr. If output file is stdout ('-') or a log
* file is specified, then all output reverts to stderr.
*
* September 27th, 2003 by Robin Miller.
* Added support for AIX.
*
* February 21st, 2002 by Robin Miller.
* Fix regression introduced by January 29th, 2002 update!
* When AIO is specified the base buffer is not setup, only the
* data buffer, so referencing this NULL pointer dumped core.
*
* January 29th, 2002 by Robin Miller.
* If compare is disabled, initialize the data buffer to be written.
* This is important to honor the user specified pattern, and to avoid
* problems writing data to tapes in compressed mode (user may wish to
* specify a non-repeating data pattern). In retrospect, it may not
* be a good idea to use !compare to disable buffer initialization,
* but changing this now will break too many folks :-)
*
* February 24th, 2001 by Robin Miller.
* Add conditionalization for QNX RTP (Neutrino).
*
* February 6th, 2001 by Robin Miller.
* Handle multiple slices to the same output file, by ensuring the
* file disposition is set to "keep". Otherwise, the first completing
* process deletes the in-use file, which is generally not desriable.
*
* avoid unexpected failures. This *is* permitted for input files.
*
* January 29th, 2001 by Robin Miller.
* Added validity checks to ensure transfer counts are modulo the
* device size, to avoid unexpected failures.
*
* January 25th, 2001 by Robin Miller.
* Added validate options function for checking options after the
* device information has been setup (i.e., device size, etc).
*
* January 15th, 2001 by Robin Miller.
* Add error checks to seek_file() and skip_file() calls.
* If reopen failures occur, don't terminate, return the error.
*
* January 14th, 2001 by Robin Miller.
* Added support for multiple volumes option.
*
* January 12th, 2001 by Robin Miller.
* When reading multiple tape files, issue a forward space file
* mark command between tape files. For systems which don't support
* tape operations, we'll use continue to use the read_eof() method.
*
* December 30th, 2000 by Robin Miller.
* Make changes to build using MKS/NuTCracker product.
*
* November 8th, 2000 by Robin Miller.
* Add check for ignoring device close failures. In this case,
* the error is displayed as a warning instead of a failure.
*
* July 14th, 2000 by Robin Miller.
* In flush_file(), control sync'ing of data using fsync flag.
*
* May 8th, 2000 by Robin Miller.
* Honor the di_closing flag, to avoid a race condition with the
* close function being called (again) while still closing, from the
* terminate() routine called by the runtime= alarm, or signals.
* [ damn, fixed this in 1994, broke it during recent re-write :-) ]
*
* April 18th, 2000 by Robin Miller.
* Added messages for open/close failures doing EEI reset tests.
* Modified calls to report_error() to ensure error count bumped.
*
* March 28th, 2000 by Robin Miller.
* Modified calls to file position functions which now accept a
* device information parameter.
*
* February 19th, 2000 by Robin Miller.
* When EEI resets are enabled, retry open/reopen failures attempts.
* Also, if we're processing EEI resets, don't fail on close().
*
* February 17th, 2000 by Robin Miller.
* Adding better support for multi-volume tape testing.
*
* January 22nd, 2000 by Robin Miller.
* Added support for Cygwin tape devices for Windows/NT.
*
* August 2, 1999 by Robin Miller.
* Don't do fsync() to tape devices to avoid errors on Linux.
*
* May 27, 1999 by Robin Miller.
* Adding support for micro-second delays.
*
* February 26, 1999 by Robin Miller.
* Adjust the file count AFTER writing a file mark, so our tape
* repositioning code will work if the Reset occurs during the WFM.
*
* December 21, 1998 by Robin Miller.
* Updates necessary to match my tape API changes.
* Save device/file open flags in device info struct.
*
* December 17, 1998 by Robin Miller.
* For DUNIX tape devices, clear persistent EEI data after opens.
*
* April 28, 1998 by Robin Miller.
* For WIN32/NT, or in O_BINARY into open flags to force binary
* mode (the default is text mode).
*
* April 7, 1998 by Robin Miller.
* Fix problem with attempting reopen of stdin/stdout.
*
* March 27, 1997 by Ali Eghlima.
* Added cluster support, so more than one process or one system
* can access a resource. dlm are being used to synchronize all
* access.
*
* December 9, 1995 by Robin Miller.
* Allow writing tape file marks on QNX Operating System.
*
* September 23, 1994 by Robin Miller.
* Make changes necessary to build on QNX 4.21 release. This
* required changing O_DSYNCH to O_DSYNC, and O_FSYNCH to O_SYNC.
*
* May 19, 1994 by Robin Miller.
* Altered logic in close_file() & reopen_file() functions to set
* the file descriptor to NoFd prior to calling close() to actually
* perform the close operation. This avoids a problem where if the
* user types Ctrl/C while the close is in progress, the signal handler
* gets invoked immediately after the system call, the fd doesn't
* get marked closed, and our termination code then attempts to
* close an already closed file descriptor and reports the error:
* "dt: 'close' - Bad file number"
*/
#include "dt.h"
#if defined(_QNX_SOURCE)
# include <fcntl.h>
#else /* !defined(_QNX_SOURCE) */
# include <sys/file.h>
#endif /* defined(_QNX_SOURCE) */
/*
* Declare the generic (default) test functions.
*/
struct dtfuncs generic_funcs = {
/* tf_open, tf_close, tf_initialize, */
open_file, close_file, initialize,
/* tf_start_test, tf_end_test, */
init_file, nofunc,
/* tf_read_file, tf_read_data, tf_cancel_reads, */
read_file, read_data, nofunc,
/* tf_write_file, tf_write_data, tf_cancel_writes, */
write_file, write_data, nofunc,
/* tf_flush_data, tf_verify_data, tf_reopen_file, */
flush_file, verify_data, reopen_file,
/* tf_startup, tf_cleanup, tf_validate_opts */
nofunc, nofunc, validate_opts
};
#if defined(MUNSA)
dlm_status_t gen_stat;
#endif /* defined(MUNSA) */
/************************************************************************
* *
* open_file() - Open an input/output file for read/write. *
* *
* Description: *
* This function does the default (generic) open processing. *
* *
* Inputs: dip = The device information pointer. *
* oflags = The device/file open flags. *
* *
* Return Value: *
* Returns 0 / -1 = SUCCESS / FAILURE. *
* *
************************************************************************/
int
open_file (struct dinfo *dip, int oflags)
{
char *file = dip->di_dname;
int status = SUCCESS;
#if defined(EEI)
int open_retries = EEI_OPEN_RETRIES;
#endif
end_of_file = FALSE;
dip->di_end_of_file = FALSE;
dip->di_end_of_media = FALSE;
dip->di_end_of_logical = FALSE;
dip->di_errno = 0;
dip->di_offset = 0L;
dip->di_position = 0;
dip->di_lba = 0;
if ( (strlen(file) == 1) && (*file == '-') ) {
if (debug_flag) {
Printf ("Dup'ing standard %s...\n",
(dip->di_ftype == INPUT_FILE) ? "input" : "output");
}
if (dip->di_ftype == INPUT_FILE) {
stdin_flag = TRUE;
dip->di_fd = dup (fileno(stdin));
} else {
ofp = efp; /* Redirect output to stderr. */
stdout_flag = TRUE;
dip->di_fd = dup (fileno(stdout));
verify_flag = FALSE;
}
if (dip->di_fd < 0) {
Fprintf ("dup -> ");
report_error (file, TRUE);
status = FAILURE;
}
} else {
#if defined(__WIN32__)
oflags |= O_BINARY;
#endif /* defined(__WIN32__) */
#if defined(EEI)
retry:
#endif
if (debug_flag) {
Printf (
"Attempting to open %s file '%s', open flags = %#o (%#x)...\n",
(dip->di_ftype == INPUT_FILE) ? "input" : "output",
file, oflags, oflags);
}
dip->di_oflags = oflags;
if (dip->di_ftype == INPUT_FILE) {
dip->di_fd = open (file, oflags);
} else {
dip->di_fd = open (file, oflags, 0666);
}
if (dip->di_fd < 0) {
char fmt[STRING_BUFFER_SIZE];
#if defined(EEI)
if ( (errno == EIO) && eei_resets &&
(dip->di_dtype &&
(dip->di_dtype->dt_dtype == DT_TAPE)) ) {
if (--open_retries) {
if (verbose_flag) {
Printf("Warning, ignoring open error and retrying...\n");
}
goto retry;
}
}
#endif /* defined(EEI) */
(void)sprintf(fmt, "open -> %s", file);
report_error (fmt, TRUE);
ExecuteTrigger(dip, "open");
status = FAILURE;
}
}
if ( (status != FAILURE) && debug_flag) {
Printf ("%s file '%s' successfully opened, fd = %d\n",
(dip->di_ftype == INPUT_FILE) ? "Input" : "Output",
file, dip->di_fd);
}
return (status);
}
/************************************************************************
* *
* close_file() - Close an open file descriptor. *
* *
* Description: *
* This function does the default (generic) close processing. *
* *
* Inputs: dip = The device information pointer. *
* *
* Return Value: *
* Returns 0 / -1 = SUCCESS / FAILURE. *
* *
************************************************************************/
int
close_file (struct dinfo *dip)
{
char *file = dip->di_dname;
int status = SUCCESS;
if (dip->di_closing || (dip->di_fd == NoFd)) {
return (status); /* Closing or not open. */
}
dip->di_closing = TRUE;
if (cdelay_count) { /* Optional close delay */
mySleep (cdelay_count);
}
if (debug_flag) {
Printf ("Closing file '%s', fd = %d...\n", file, dip->di_fd);
}
if ((status = close (dip->di_fd)) == FAILURE) {
if (cerrors_flag) {
report_error ("close", TRUE);
ExecuteTrigger(dip, "close");
} else if (verbose_flag) {
status = SUCCESS;
Printf("Warning, close failed, errno = %d - %s\n",
errno, strerror(errno));
Printf("Warning, ignoring close failure and continuing...\n");
}
#if defined(EEI)
if ( (errno == EIO) && eei_resets &&
(dip->di_dtype->dt_dtype == DT_TAPE) ) {
if (dip->di_proc_eei) {
if (verbose_flag) {
Printf("Warning, ignoring close failure and continuing...\n");
}
error_count--;
status = SUCCESS;
}
/* No retries, we're already closed! */
}
#endif /* defined(EEI) */
}
dip->di_fd = NoFd;
dip->di_closing = FALSE;
return (status);
}
/************************************************************************
* *
* reopen_file() - Close and reopen file descriptor. *
* *
* Inputs: dip = The device information pointer. *
* oflags = The device/file open flags. *
* *
* Return Value: *
* Returns 0 / -1 = SUCCESS / FAILURE. *
* *
************************************************************************/
int
reopen_file (struct dinfo *dip, int oflags)
{
struct dtfuncs *dtf = dip->di_funcs;
char *file = dip->di_dname;
int status = SUCCESS;
#if defined(EEI)
int open_retries = EEI_OPEN_RETRIES;
#endif
/*
* For stdin or stdout, do not attempt close/open.
*/
if ( (strlen(file) == 1) && (*file == '-') ) return (status);
/*
* For tape, we must close & reopen to get to BOT,
* an lseek() won't do the trick.
*/
if (dip->di_fd != NoFd) { /* If not already closed... */
status = (*dtf->tf_close)(dip);
}
if (edelay_count) { /* Optional end delay. */
mySleep (edelay_count);
}
end_of_file = FALSE;
dip->di_end_of_file = FALSE;
dip->di_end_of_media = FALSE;
dip->di_end_of_logical = FALSE;
dip->di_errno = 0;
dip->di_offset = 0L;
dip->di_position = 0;
dip->di_lba = 0;
#if defined(__WIN32__)
oflags |= O_BINARY;
#endif /* defined(__WIN32__) */
#if defined(EEI)
retry:
#endif
if (debug_flag) {
Printf ("Attempting to reopen file '%s', open flags = %#o (%#x)...\n",
file, oflags, oflags);
}
dip->di_oflags = oflags;
if ( (dip->di_fd = open (file, oflags)) == FAILURE) {
#if defined(EEI)
if ( (dip->di_dtype->dt_dtype == DT_TAPE) &&
(errno == EIO) && eei_resets) {
if (--open_retries) {
if (verbose_flag) {
Printf("Warning, ignoring open error and retrying...\n");
}
goto retry;
}
}
#endif /* defined(EEI) */
report_error ("reopen", TRUE);
ExecuteTrigger(dip, "open");
return (FAILURE);
}
if (debug_flag) {
Printf ("File '%s' successfully reopened, fd = %d\n",
file, dip->di_fd);
}
#if defined(EEI)
if ( (status == SUCCESS) && eei_flag &&
(dip->di_dtype->dt_dtype == DT_TAPE) ) {
clear_eei_status(dip->di_fd, FALSE);
}
#endif /* defined(EEI) */
return (status);
}
/************************************************************************
* *
* initialize() - Do the default program initialization. *
* *
* Description: *
* This function does the default (generic) test initialization. *
* *
* Inputs: dip = The device information pointer. *
* *
* Outputs: Always SUCCESS right now. *
* *
************************************************************************/
int
initialize (struct dinfo *dip)
{
if (!data_buffer) {
base_buffer = data_buffer = myalloc (data_size, align_offset);
}
return (SUCCESS);
}
/************************************************************************
* *
* init_file() - Initial file processing. *
* *
* Description: *
* This function is used to process options before starting tests. *
* *
* Inputs: dip = The device information pointer. *
* *
* Outputs: Always SUCCESS right now. *
* *
************************************************************************/
int
init_file (struct dinfo *dip)
{
int status = SUCCESS;
int fd = dip->di_fd;
/*
* If the lba option is specified, and we're a disk device,
* then setup a file position to be seek'ed to below.
*/
if ( lbdata_addr && !user_position &&
((dip->di_dtype->dt_dtype == DT_DISK) ||
(dip->di_dtype->dt_dtype == DT_BLOCK)) ) {
file_position = make_position(dip, lbdata_addr);
if ( (io_type == RANDOM_IO) && (rdata_limit <= file_position) ) {
LogMsg (efp, logLevelCrit, 0,
"Please specify a random data limit > lba file position!\n");
exit (FATAL_ERROR);
}
}
/*
* Seek to specified offset (if requested).
*/
if (file_position) {
last_position = set_position (dip, file_position);
}
/*
* Seek to specified record (if requested).
*/
if (seek_count) {
#if defined(_BSD)
last_position = seek_file (fd, seek_count, block_size, L_INCR);
#else /* !defined(_BSD) */
last_position = seek_file (fd, seek_count, block_size, SEEK_CUR);
#endif /* defined(_BSD) */
if (last_position == (off_t) FAILURE) return (FAILURE);
show_position (dip, last_position);
}
/*
* Skip over input record(s) (if requested).
*/
if (skip_count) {
status = skip_records (dip, skip_count, data_buffer, block_size);
if (debug_flag && (status != FAILURE)) {
Printf ("Successfully skipped %d records.\n", skip_count);
}
}
return (status);
}
/************************************************************************
* *
* flush_file() - Flush file data to disk. *
* *
* Description: *
* This function is used to flush the file data to disk after the *
* write pass of each test. *
* *
* Inputs: dip = The device information pointer. *
* *
* Return Value: *
* Returns SUCCESS / FAILURE = Ok / Sync Failed. *
* *
************************************************************************/
int
flush_file (struct dinfo *dip)
{
int status = SUCCESS;
int fd = dip->di_fd;
/*
* Ensure data is sync'ed to disk file.
*/
if ( fsync_flag ) {
if (debug_flag) {
Printf ("Flushing data to file '%s'...\n", dip->di_dname);
}
#if defined(_QNX_SOURCE)
if ((status = fcntl (fd, F_SETFL, O_DSYNC)) < 0) {
report_error("F_SETFL", TRUE);
}
#else /* !defined(_QNX_SOURCE) */
if ((status = fsync (fd)) < 0) { /* Force data to disk. */
report_error ("fsync", TRUE);
}
#endif /* !defined(_QNX_SOURCE) */
}
return (status);
}
/************************************************************************
* *
* read_file - Read and optionally verify data in the test file. *
* *
* Inputs: dip = The device information pointer. *
* *
* Return Value: *
* Returns SUCCESS/FAILURE = Ok / Error. *
* *
************************************************************************/
int
read_file (struct dinfo *dip)
{
int status;
struct dtfuncs *dtf = dip->di_funcs;
#if defined(MUNSA)
if (munsa_flag) {
if (debug_flag) {
Printf ("converting to dlm NL-> %d \n",
input_munsa_lock_type);
}
gen_stat = dlm_cvt(&lkid, input_munsa_lock_type,
NULL, 0, 0, 0, NULL, 0);
if (gen_stat != DLM_SUCCESS) {
Fprintf ("dlm_cvt failed\n");
dlm_error(&lkid, gen_stat); /* exit with FATAL ERROR */
}
if (debug_flag) {
Printf ("done, converting to dlm NL-> %d \n",
input_munsa_lock_type);
}
} /* end if(munsa_flag) .... */
#endif /* defined(MUNSA) */
dip->di_offset = make_offset(dip, lbdata_addr);
/*
* Loop reading/comparing data until we've detected end of file
* or we've reached the data limit or record limit.
*/
do { /* Read/compare data. */
dip->di_fbytes_read =(v_large) 0;
dip->di_records_read = (v_large) 0;
read_some_more:
if ((status = (*dtf->tf_read_data)(dip)) == FAILURE) break;
if (volumes_flag && (multi_volume >= volume_limit) &&
(dip->di_volume_records >= volume_records)) {
break;
}
/*
* Handle reading multiple tapes and multiple files.
*/
if (end_of_file && multi_flag &&
(dip->di_dtype->dt_dtype == DT_TAPE) &&
((dip->di_records_read != record_limit) &&
(dip->di_fbytes_read != data_limit)) ) {
/* Check for logical end of tape. */
(void) (*dtf->tf_cancel_reads)(dip);
if ((status = read_eom(dip)) != SUCCESS) break;
if ( !end_of_file ) goto read_some_more;
}
if (end_of_file) dip->di_files_read++;
if ( (dip->di_dtype->dt_dtype == DT_TAPE) &&
(file_limit && (dip->di_files_read < file_limit)) ) {
/*
* Normally, we handle EOF conditions on the fly, but when lbdata
* or the IOT pattern is enabled, we must cancel outstanding I/O's
* so that aio_offset (for LBA) is accurate on subsequent files.
*/
if (lbdata_flag || iot_pattern) {
(void) (*dtf->tf_cancel_reads)(dip);
}
/*
* An exact record or data limit keeps us short of file marks,
* so we read and check for an expected end of file here.
*/
if (!end_of_file) {
#if defined(__NUTC__) || defined(__QNXNTO__) || defined(AIX)
if ((status = read_eof(dip)) != SUCCESS) break;
#else /* !defined(__NUTC__) && !defined(__QNXNTO__) && !defined(AIX) */
status = DoForwardSpaceFile (dip, (daddr_t) 1);
if (status != SUCCESS) break;
#endif /* defined(__NUTC__) || defined(__QNXNTO__) || defined(AIX) */
if (++dip->di_files_read == file_limit) break;
}
dip->di_fbytes_read =(v_large) 0;
dip->di_records_read = (v_large) 0;
end_of_file = FALSE;
continue;
}
} while ( !end_of_file && (error_count < error_limit) &&
(dip->di_records_read < record_limit) &&
(dip->di_fbytes_read < data_limit) );
/*
* We cancel the reads here incase multiple files were being
* read, so reads continue while we process each file mark.
*/
(void) (*dtf->tf_cancel_reads)(dip);
return (status);
}
/************************************************************************
* *
* write_file() - Write data to the test file/device. *
* *
* Inputs: dip = The device information pointer. *
* *
* Return Value: *
* Returns SUCCESS/FAILURE = Ok/Error. *
* *
************************************************************************/
int
write_file (struct dinfo *dip)
{
int status;
struct dtfuncs *dtf = dip->di_funcs;
#if defined(MUNSA)
if (munsa_flag) {
if (debug_flag) {
Printf ("converting to dlm NL-> %d .\n",
output_munsa_lock_type);
}
gen_stat = dlm_cvt(&lkid, output_munsa_lock_type,
NULL, 0, 0, 0, NULL, 0);
if (gen_stat != DLM_SUCCESS) {
Fprintf ("dlm_cvt failed\n");
dlm_error(&lkid, gen_stat); /* exit with FATAL ERROR */
}
if (debug_flag) {
Printf ("done, converting to dlm NL-> %d .\n",
output_munsa_lock_type);
}
} /* end if(munsa_flag)... */
#endif /* defined(MUNSA) */
dip->di_offset = make_offset(dip, lbdata_addr);
/*
* Initialize the data buffer with a pattern if compare is
* disabled, so we honor the user specified pattern.
*/
if ((io_mode == TEST_MODE) && !compare_flag) {
if (iot_pattern) {
u_int32 lba = make_lbdata (dip, dip->di_offset);
(void)init_iotdata(block_size, lba, lbdata_size);
}
fill_buffer (data_buffer, block_size, pattern);
}
/*
* Loop writing data until end of media or data limit reached.
*/
do { /* Write data pattern. */
if (raw_flag) {
dip->di_fbytes_read = (v_large) 0;
dip->di_records_read = (v_large) 0;
}
dip->di_fbytes_written = (v_large) 0;
dip->di_records_written = (v_large) 0;
if ((status = (*dtf->tf_write_data)(dip)) == FAILURE) break;
if (volumes_flag && (multi_volume >= volume_limit) &&
(dip->di_volume_records >= volume_records)) {
break;
}
/*
* Handle writing multiple tape files.
*/
if ( (dip->di_dtype->dt_dtype == DT_TAPE) &&
(file_limit && (dip->di_files_written < file_limit)) ) {
/*
* For tapes, write a file mark for all but last file.
* The last file mark(s) are written when closing tape.
*/
#if !defined(__NUTC__) && !defined(__QNXNTO__) && !defined(AIX)
if ((dip->di_files_written + 1) < file_limit) {
status = DoWriteFileMark (dip, (daddr_t) 1);
if (status != SUCCESS) break;
}
#endif /* !defined(__NUTC__) && !defined(__QNXNTO__) && !defined(AIX) */
if (++dip->di_files_written < file_limit) {
dip->di_fbytes_written =(v_large) 0;
dip->di_records_written = (v_large) 0;
continue; /* Write the next file. */
}
}
} while ( !end_of_file && (error_count < error_limit) &&
(dip->di_records_written < record_limit) &&
(dip->di_fbytes_written < data_limit) );
return (status);
}
/************************************************************************
* *
* validate_opts() - Generic Validate Option Test Criteria. *
* *
* Description: *
* This function verifies the options specified are valid for the *
* test criteria selected. *
* *
* Inputs: dip = The device information pointer. *
* *
* Return Value: *
* Returns SUCESS / FAILURE = Valid / Invalid Options. *
* *
************************************************************************/
int
validate_opts (struct dinfo *dip)
{
if (bypass_flag) return (SUCCESS);
if (dip->di_fd == NoFd) {
/*
* Validation checks *before* the device is open.
*/
if (min_size && (dip->di_dtype->dt_dtype != DT_REGULAR)) {
size_t value;
char *emsg = NULL;
if (dip->di_dsize > min_size) {
value = min_size; emsg = "min size";
} else if (dip->di_dsize > max_size) {
value = max_size; emsg = "max size";
}
if (emsg) {
Fprintf(
"Please specify %s (%u) greater than device size %u of bytes.\n",
emsg, value, dip->di_dsize);
return (FAILURE);
}
}
} else {
/*
* Validation checks *after* the device is open.
*/
if ( (dip->di_dtype->dt_dtype == DT_REGULAR) &&
(dip->di_ftype == OUTPUT_FILE) &&
num_slices && (dispose_mode == DELETE_FILE) ) {
dispose_mode = KEEP_FILE;
if (verbose_flag) {
Printf("Warning: Multiple slices to same file, setting dispose=keep!\n");
}
}
if ( (io_dir == REVERSE) || (io_type == RANDOM_IO) ) {
if ( !dip->di_random_access ) {
Fprintf(
"Random I/O or reverse direction, is only valid for random access device!\n");
return (FAILURE);
}
if ( (dip->di_dtype->dt_dtype == DT_REGULAR) && !user_capacity ) {
Fprintf(
"Please specify a data limit, record count, or capacity for random I/O.\n");
return (FAILURE);
}
}
/*
* Note: Non-modulo device sizes permitted to regular files!
*/
if (dip->di_random_access && (dip->di_dtype->dt_dtype != DT_REGULAR) ) {
size_t value;
char *emsg = NULL;
if (block_size % dip->di_dsize) {
value = block_size; emsg = "block size";
} else if (min_size && (min_size % dip->di_dsize)) {
value = min_size; emsg = "min size";
} else if (max_size && (max_size % dip->di_dsize)) {
value = max_size; emsg = "max size";
} else if (incr_count && (incr_count % dip->di_dsize)) {
value = incr_count; emsg = "incr count";
}
if (emsg) {
Fprintf(
"Please specify a %s (%u) modulo the device size of %u bytes!\n",
emsg, value, dip->di_dsize);
return (FAILURE);
}
}
}
return (SUCCESS);
}
syntax highlighted by Code2HTML, v. 0.9.1