1 /*
2 * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@strace.io>
3 * Copyright (c) 2016-2021 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #ifdef HAVE_PREADV
12
13 # include <fcntl.h>
14 # include <stdio.h>
15 # include <sys/uio.h>
16 # include <unistd.h>
17
18 # define LEN 8
19
20 static void
21 print_iov(const struct iovec *iov)
22 {
23 unsigned char *buf = iov->iov_base;
24
25 fputs("{iov_base=\"", stdout);
26 for (unsigned int i = 0; i < iov->iov_len; ++i)
27 printf("\\%d", (int) buf[i]);
28 printf("\", iov_len=%u}", (unsigned) iov->iov_len);
29 }
30
31 static void
32 print_iovec(const struct iovec *iov, unsigned int cnt)
33 {
34 putchar('[');
35 for (unsigned int i = 0; i < cnt; ++i) {
36 if (i)
37 fputs(", ", stdout);
38 print_iov(&iov[i]);
39 }
40 putchar(']');
41 }
42
43 /* for preadv(0, NULL, 1, -2) */
44 DIAG_PUSH_IGNORE_NONNULL
45
46 int
47 main(void)
48 {
49 const off_t offset = 0xdefaceddeadbeefLL;
50 char *buf = tail_alloc(LEN);
51 TAIL_ALLOC_OBJECT_CONST_PTR(struct iovec, iov);
52 iov->iov_base = buf;
53 iov->iov_len = LEN;
54
55 (void) close(0);
56 if (open("/dev/zero", O_RDONLY))
57 perror_msg_and_fail("open");
58
59 if (preadv(0, iov, 1, offset) != LEN)
60 perror_msg_and_fail("preadv");
61 printf("preadv(0, ");
62 print_iovec(iov, 1);
63 printf(", 1, %lld) = %u\n", (long long) offset, LEN);
64
65 if (preadv(0, iov, 1, -1) != -1)
66 perror_msg_and_fail("preadv");
67 printf("preadv(0, [{iov_base=%p, iov_len=%zu}], 1, -1) = "
68 "-1 EINVAL (%m)\n", iov->iov_base, iov->iov_len);
69
70 if (preadv(0, NULL, 1, -2) != -1)
71 perror_msg_and_fail("preadv");
72 printf("preadv(0, NULL, 1, -2) = -1 EINVAL (%m)\n");
73
74 if (preadv(0, iov, 0, -3) != -1)
75 perror_msg_and_fail("preadv");
76 printf("preadv(0, [], 0, -3) = -1 EINVAL (%m)\n");
77
78 int fd = create_tmpfile(O_RDWR);
79
80 static const char w[] = "0123456789abcde";
81 if (write(fd, w, LENGTH_OF(w)) != LENGTH_OF(w))
82 perror_msg_and_fail("write");
83
84 static const char r0_c[] = "01234567";
85 static const char r1_c[] = "89abcde";
86
87 const unsigned int r_len = (LENGTH_OF(w) + 1) / 2;
88 void *r0 = tail_alloc(r_len);
89 const struct iovec r0_iov_[] = {
90 {
91 .iov_base = r0,
92 .iov_len = r_len
93 }
94 };
95 const struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_));
96
97 long rc;
98
99 rc = preadv(fd, r_iov, ARRAY_SIZE(r0_iov_), 0);
100 if (rc != (int) r_len)
101 perror_msg_and_fail("preadv: expected %u, returned %ld",
102 r_len, rc);
103 printf("preadv(%d, [{iov_base=\"%s\", iov_len=%u}], %u, 0) = %u\n",
104 fd, r0_c, r_len, (unsigned int) ARRAY_SIZE(r0_iov_), r_len);
105
106 void *r1 = tail_alloc(r_len);
107 void *r2 = tail_alloc(LENGTH_OF(w));
108 const struct iovec r1_iov_[] = {
109 {
110 .iov_base = r1,
111 .iov_len = r_len
112 },
113 {
114 .iov_base = r2,
115 .iov_len = LENGTH_OF(w)
116 }
117 };
118 r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_));
119
120 rc = preadv(fd, r_iov, ARRAY_SIZE(r1_iov_), r_len);
121 if (rc != (int) LENGTH_OF(w) - (int) r_len)
122 perror_msg_and_fail("preadv: expected %d, returned %ld",
123 (int) LENGTH_OF(w) - r_len, rc);
124 printf("preadv(%d, [{iov_base=\"%s\", iov_len=%u}"
125 ", {iov_base=\"\", iov_len=%u}], %u, %u) = %u\n",
126 fd, r1_c, r_len, LENGTH_OF(w),
127 (unsigned int) ARRAY_SIZE(r1_iov_),
128 r_len, LENGTH_OF(w) - r_len);
129
130 puts("+++ exited with 0 +++");
131 return 0;
132 }
133
134 DIAG_POP_IGNORE_NONNULL
135
136 #else
137
138 SKIP_MAIN_UNDEFINED("HAVE_PREADV")
139
140 #endif