238 lines
5.2 KiB
C
238 lines
5.2 KiB
C
/*
|
|
*
|
|
* Copyright (c) International Business Machines Corp., 2002
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
* the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* NAME
|
|
* diotest_routines.c
|
|
*
|
|
* DESCRIPTION
|
|
* Functions that are used in diotest programs.
|
|
* fillbuf(), bufcmp(), filecmp()
|
|
* forkchldrn(), waitchldrn(), killchldrn()
|
|
*
|
|
* History
|
|
* 04/10/2002 Narasimha Sharoff
|
|
*
|
|
* RESTRICTIONS
|
|
* None
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/uio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
#include "diotest_routines.h"
|
|
|
|
/* **** Routines for buffer actions, comparisions **** */
|
|
|
|
/*
|
|
* fillbuf: Fill buffer of given size with given character value
|
|
* vfillbuf: Fill the vector array
|
|
*/
|
|
void fillbuf(char *buf, int count, char value)
|
|
{
|
|
while (count > 0) {
|
|
strncpy(buf, &value, 1);
|
|
buf++;
|
|
count = count - 1;
|
|
}
|
|
}
|
|
|
|
void vfillbuf(struct iovec *iv, int vcnt, char value)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < vcnt; iv++, i++) {
|
|
fillbuf(iv->iov_base, iv->iov_len, (char)value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* bufcmp: Compare two buffers
|
|
* vbufcmp: Compare two buffers of two io arrays
|
|
*/
|
|
int bufcmp(char *b1, char *b2, int bsize)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < bsize; i++) {
|
|
if (strncmp(&b1[i], &b2[i], 1)) {
|
|
fprintf(stderr,
|
|
"bufcmp: offset %d: Expected: 0x%x, got 0x%x\n",
|
|
i, b1[i], b2[i]);
|
|
return (-1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
int vbufcmp(struct iovec *iv1, struct iovec *iv2, int vcnt)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < vcnt; iv1++, iv2++, i++) {
|
|
if (bufcmp(iv1->iov_base, iv2->iov_base, iv1->iov_len) < 0) {
|
|
fprintf(stderr, "Vector: %d, iv1base=%s, iv2base=%s\n",
|
|
i, (char *)iv1->iov_base,
|
|
(char *)iv2->iov_base);
|
|
return (-1);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* compare_files: Compares two files
|
|
*/
|
|
int filecmp(char *f1, char *f2)
|
|
{
|
|
int i;
|
|
int fd1, fd2;
|
|
int ret1, ret2 = 0;
|
|
char buf1[BUFSIZ], buf2[BUFSIZ];
|
|
|
|
/* Open the file for read */
|
|
if ((fd1 = open(f1, O_RDONLY)) == -1) {
|
|
fprintf(stderr, "compare_files: open failed %s: %s",
|
|
f1, strerror(errno));
|
|
return (-1);
|
|
}
|
|
if ((fd2 = open(f2, O_RDONLY)) == -1) {
|
|
fprintf(stderr, "compare_files: open failed %s: %s",
|
|
f2, strerror(errno));
|
|
close(fd1);
|
|
return (-1);
|
|
}
|
|
|
|
/* Compare the files */
|
|
while ((ret1 = read(fd1, buf1, BUFSIZ)) > 0) {
|
|
ret2 = read(fd2, buf2, BUFSIZ);
|
|
if (ret1 != ret2) {
|
|
fprintf(stderr, "compare_file: file length mistmatch:");
|
|
fprintf(stderr, "read: %d from %s, %d from %s",
|
|
ret1, f1, ret2, f2);
|
|
close(fd1);
|
|
close(fd2);
|
|
return (-1);
|
|
}
|
|
for (i = 0; i < ret1; i++) {
|
|
if (strncmp(&buf1[i], &buf2[i], 1)) {
|
|
fprintf(stderr, "compare_file: char mismatch:");
|
|
fprintf(stderr, " %s offset %d: 0x%02x %c ",
|
|
f1, i, buf1[i],
|
|
isprint(buf1[i]) ? buf1[1] : '.');
|
|
fprintf(stderr, " %s offset %d: 0x%02x %c\n",
|
|
f2, i, buf2[i],
|
|
isprint(buf2[i]) ? buf2[i] : '.');
|
|
close(fd1);
|
|
close(fd2);
|
|
return (-1);
|
|
}
|
|
}
|
|
}
|
|
close(fd1);
|
|
close(fd2);
|
|
return 0;
|
|
}
|
|
|
|
/* **** Routines to create, wait and destroy child processes **** */
|
|
|
|
/*
|
|
* forkchldrn: fork the given number of children and set the function
|
|
* that child should execute.
|
|
*/
|
|
int forkchldrn(int **pidlst, int numchld, int action, int (*chldfunc) ())
|
|
{
|
|
int i, cpid;
|
|
|
|
if ((*pidlst = ((int *)malloc(sizeof(int) * numchld))) == 0) {
|
|
fprintf(stderr, "forkchldrn: calloc failed for pidlst: %s\n",
|
|
strerror(errno));
|
|
return (-1);
|
|
}
|
|
for (i = 0; i < numchld; i++) {
|
|
if ((cpid = fork()) < 0) {
|
|
fprintf(stderr,
|
|
"forkchldrn: fork child %d failed, %s\n", i,
|
|
strerror(errno));
|
|
killchldrn(pidlst, i, SIGTERM);
|
|
return (-1);
|
|
}
|
|
if (cpid == 0)
|
|
exit((*chldfunc) (i, action));
|
|
else
|
|
*(*pidlst + i) = cpid;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* killchldrn: signal the children listed in pidlst with the given signal
|
|
*
|
|
*/
|
|
int killchldrn(int **pidlst, int numchld, int sig)
|
|
{
|
|
int i, cpid, errflag = 0;
|
|
|
|
for (i = 0; i < numchld; i++) {
|
|
cpid = *(*pidlst + i);
|
|
if (cpid > 0) {
|
|
if (kill(cpid, sig) < 0) {
|
|
fprintf(stderr,
|
|
"killchldrn: kill %d failed, %s\n",
|
|
cpid, strerror(errno));
|
|
errflag--;
|
|
}
|
|
}
|
|
}
|
|
return (errflag);
|
|
}
|
|
|
|
/*
|
|
* waitchldrn: wait for child process listed in pidlst to finish.
|
|
*/
|
|
int waitchldrn(int **pidlst, int numchld)
|
|
{
|
|
int i, cpid, ret, errflag = 0;
|
|
int status;
|
|
|
|
for (i = 0; i < numchld; i++) {
|
|
cpid = *(*pidlst + i);
|
|
if (cpid == 0)
|
|
continue;
|
|
if ((ret = waitpid(cpid, &status, 0)) != cpid) {
|
|
fprintf(stderr,
|
|
"waitchldrn: wait failed for child %d, pid %d: %s\n",
|
|
i, cpid, strerror(errno));
|
|
errflag--;
|
|
}
|
|
if (status)
|
|
errflag = -1;
|
|
}
|
|
return (errflag);
|
|
}
|