1 /*
2  * Check that fault injection works properly.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "tests.h"
31 
32 #include <assert.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39 #include <sys/uio.h>
40 
41 static const int expfd = 4;
42 static const int gotfd = 5;
43 
44 #define DEFAULT_ERRNO ENOSYS
45 
46 static const char *errstr;
47 static int is_raw, err, first, step, iter, try;
48 
49 static void
invoke(int fail)50 invoke(int fail)
51 {
52 	static char buf[sizeof(int) * 3 + 3];
53 	const struct iovec io = {
54 		.iov_base = buf,
55 		.iov_len = sprintf(buf, "%d.", ++try)
56 	};
57 	int rc;
58 
59 	if (!fail) {
60 		rc = write(expfd, io.iov_base, io.iov_len);
61 		if (rc != (int) io.iov_len)
62 			perror_msg_and_fail("write");
63 	}
64 
65 	errno = 0;
66 	rc = writev(gotfd, &io, 1);
67 
68 	if (fail) {
69 		if (!(rc == -1 && errno == err))
70 			perror_msg_and_fail("expected errno %d"
71 					    ", got rc == %d, errno == %d",
72 					    err, rc, errno);
73 
74 		if (is_raw)
75 			tprintf("writev(%#x, %p, 0x1) = -1 (errno %d)"
76 				" (INJECTED)\n", gotfd, &io, err);
77 		else
78 			tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
79 				" = -1 %s (%m) (INJECTED)\n",
80 				gotfd, buf, (int) io.iov_len, errstr);
81 	} else {
82 		if (rc != (int) io.iov_len)
83 			perror_msg_and_fail("expected %d"
84 					    ", got rc == %d, errno == %d",
85 					    (int) io.iov_len, rc, errno);
86 
87 		if (is_raw)
88 			tprintf("writev(%#x, %p, 0x1) = %#x\n", gotfd, &io, rc);
89 		else
90 			tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
91 				" = %d\n",
92 				gotfd, buf, (int) io.iov_len, (int) io.iov_len);
93 	}
94 }
95 
96 int
main(int argc,char * argv[])97 main(int argc, char *argv[])
98 {
99 	struct stat st;
100 
101 	assert(fstat(expfd, &st) == 0);
102 	assert(fstat(gotfd, &st) == 0);
103 
104 	assert(argc == 6);
105 
106 	is_raw = !strcmp("raw", argv[1]);
107 
108 	errstr = argv[2];
109 	err = atoi(errstr);
110 	assert(err >= 0);
111 
112 	if (!err) {
113 		if (!*errstr)
114 			err = DEFAULT_ERRNO;
115 		else if (!strcasecmp(errstr, "EINVAL"))
116 			err = EINVAL;
117 		else
118 			err = ENOSYS;
119 	}
120 
121 	errno = err;
122 	errstr = errno2name();
123 
124 	first = atoi(argv[3]);
125 	step = atoi(argv[4]);
126 	iter = atoi(argv[5]);
127 
128 	assert(first > 0);
129 	assert(step >= 0);
130 
131 	tprintf("%s", "");
132 
133 	int i;
134 	for (i = 1; i <= iter; ++i) {
135 		int fail = 0;
136 		if (first > 0) {
137 			--first;
138 			if (first == 0) {
139 				fail = 1;
140 				first = step;
141 			}
142 		}
143 		invoke(fail);
144 	}
145 
146 	tprintf("%s\n", "+++ exited with 0 +++");
147 	return 0;
148 }
149