1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2002
4 *
5 *   This program is free software;  you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 *   the GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program;  if not, write to the Free Software
17 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * NAME
22 *      diotest_routines.c
23 *
24 * DESCRIPTION
25 *	Functions that are used in diotest programs.
26 *	fillbuf(), bufcmp(), filecmp()
27 *	forkchldrn(), waitchldrn(), killchldrn()
28 *
29 * History
30 *	04/10/2002	Narasimha Sharoff
31 *
32 * RESTRICTIONS
33 *	None
34*/
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <signal.h>
40#include <fcntl.h>
41#include <sys/types.h>
42#include <sys/wait.h>
43#include <sys/uio.h>
44#include <errno.h>
45#include <unistd.h>
46#include <ctype.h>
47
48#include "diotest_routines.h"
49
50/* **** Routines for buffer actions, comparisions **** */
51
52/*
53 * fillbuf: Fill buffer of given size with given character value
54 * vfillbuf: Fill the vector array
55*/
56void fillbuf(char *buf, int count, char value)
57{
58	while (count > 0) {
59		strncpy(buf, &value, 1);
60		buf++;
61		count = count - 1;
62	}
63}
64
65void vfillbuf(struct iovec *iv, int vcnt, char value)
66{
67	int i;
68
69	for (i = 0; i < vcnt; iv++, i++) {
70		fillbuf(iv->iov_base, iv->iov_len, (char)value);
71	}
72}
73
74/*
75 * bufcmp: Compare two buffers
76 * vbufcmp: Compare two buffers of two io arrays
77*/
78int bufcmp(char *b1, char *b2, int bsize)
79{
80	int i;
81
82	for (i = 0; i < bsize; i++) {
83		if (strncmp(&b1[i], &b2[i], 1)) {
84			fprintf(stderr,
85				"bufcmp: offset %d: Expected: 0x%x, got 0x%x\n",
86				i, b1[i], b2[i]);
87			return (-1);
88		}
89	}
90	return (0);
91}
92
93int vbufcmp(struct iovec *iv1, struct iovec *iv2, int vcnt)
94{
95	int i;
96
97	for (i = 0; i < vcnt; iv1++, iv2++, i++) {
98		if (bufcmp(iv1->iov_base, iv2->iov_base, iv1->iov_len) < 0) {
99			fprintf(stderr, "Vector: %d, iv1base=%s, iv2base=%s\n",
100				i, (char *)iv1->iov_base,
101				(char *)iv2->iov_base);
102			return (-1);
103		}
104	}
105	return 0;
106}
107
108/*
109 * compare_files: Compares two files
110*/
111int filecmp(char *f1, char *f2)
112{
113	int i;
114	int fd1, fd2;
115	int ret1, ret2 = 0;
116	char buf1[BUFSIZ], buf2[BUFSIZ];
117
118	/* Open the file for read */
119	if ((fd1 = open(f1, O_RDONLY)) == -1) {
120		fprintf(stderr, "compare_files: open failed %s: %s",
121			f1, strerror(errno));
122		return (-1);
123	}
124	if ((fd2 = open(f2, O_RDONLY)) == -1) {
125		fprintf(stderr, "compare_files: open failed %s: %s",
126			f2, strerror(errno));
127		close(fd1);
128		return (-1);
129	}
130
131	/* Compare the files */
132	while ((ret1 = read(fd1, buf1, BUFSIZ)) > 0) {
133		ret2 = read(fd2, buf2, BUFSIZ);
134		if (ret1 != ret2) {
135			fprintf(stderr, "compare_file: file length mistmatch:");
136			fprintf(stderr, "read: %d from %s, %d from %s",
137				ret1, f1, ret2, f2);
138			close(fd1);
139			close(fd2);
140			return (-1);
141		}
142		for (i = 0; i < ret1; i++) {
143			if (strncmp(&buf1[i], &buf2[i], 1)) {
144				fprintf(stderr, "compare_file: char mismatch:");
145				fprintf(stderr, " %s offset %d: 0x%02x %c  ",
146					f1, i, buf1[i],
147					isprint(buf1[i]) ? buf1[1] : '.');
148				fprintf(stderr, " %s offset %d: 0x%02x %c\n",
149					f2, i, buf2[i],
150					isprint(buf2[i]) ? buf2[i] : '.');
151				close(fd1);
152				close(fd2);
153				return (-1);
154			}
155		}
156	}
157	close(fd1);
158	close(fd2);
159	return 0;
160}
161
162/* **** Routines to create, wait and destroy child processes **** */
163
164/*
165 * forkchldrn: fork the given number of children and set the function
166 *		that child should execute.
167*/
168int forkchldrn(int **pidlst, int numchld, int action, int (*chldfunc) ())
169{
170	int i, cpid;
171
172	if ((*pidlst = ((int *)malloc(sizeof(int) * numchld))) == 0) {
173		fprintf(stderr, "forkchldrn: calloc failed for pidlst: %s\n",
174			strerror(errno));
175		return (-1);
176	}
177	for (i = 0; i < numchld; i++) {
178		if ((cpid = fork()) < 0) {
179			fprintf(stderr,
180				"forkchldrn: fork child %d failed, %s\n", i,
181				strerror(errno));
182			killchldrn(pidlst, i, SIGTERM);
183			return (-1);
184		}
185		if (cpid == 0)
186			exit((*chldfunc) (i, action));
187		else
188			*(*pidlst + i) = cpid;
189	}
190	return 0;
191}
192
193/*
194 * killchldrn: signal the children listed in pidlst with the given signal
195 *
196*/
197int killchldrn(int **pidlst, int numchld, int sig)
198{
199	int i, cpid, errflag = 0;
200
201	for (i = 0; i < numchld; i++) {
202		cpid = *(*pidlst + i);
203		if (cpid > 0) {
204			if (kill(cpid, sig) < 0) {
205				fprintf(stderr,
206					"killchldrn: kill %d failed, %s\n",
207					cpid, strerror(errno));
208				errflag--;
209			}
210		}
211	}
212	return (errflag);
213}
214
215/*
216 * waitchldrn: wait for child process listed in pidlst to finish.
217*/
218int waitchldrn(int **pidlst, int numchld)
219{
220	int i, cpid, ret, errflag = 0;
221	int status;
222
223	for (i = 0; i < numchld; i++) {
224		cpid = *(*pidlst + i);
225		if (cpid == 0)
226			continue;
227		if ((ret = waitpid(cpid, &status, 0)) != cpid) {
228			fprintf(stderr,
229				"waitchldrn: wait failed for child %d, pid %d: %s\n",
230				i, cpid, strerror(errno));
231			errflag--;
232		}
233		if (status)
234			errflag = -1;
235	}
236	return (errflag);
237}
238