/*
*
* 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);
}