(root)/
strace-6.5/
tests/
preadv2-pwritev2.c
       1  /*
       2   * Check decoding of preadv2 and pwritev2 syscalls.
       3   *
       4   * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include "scno.h"
      13  
      14  #include <errno.h>
      15  #include <fcntl.h>
      16  #include <stdio.h>
      17  #include <sys/uio.h>
      18  #include <unistd.h>
      19  
      20  static int
      21  pr(const int fd, const struct iovec *const vec,
      22     const unsigned long vlen, const unsigned long pos)
      23  {
      24  	return syscall(__NR_preadv2, fd, vec, vlen, pos, 0L, 0L);
      25  }
      26  
      27  static int
      28  pw(const int fd, const struct iovec *const vec,
      29     const unsigned long vlen, const unsigned long pos)
      30  {
      31  	return syscall(__NR_pwritev2, fd, vec, vlen, pos, 0L, 0L);
      32  }
      33  
      34  static void
      35  dumpio(void)
      36  {
      37  	static char tmp[] = "preadv2-pwritev2-tmpfile";
      38  	if (open(tmp, O_CREAT|O_RDONLY|O_TRUNC, 0600) != 0)
      39  		perror_msg_and_fail("creat: %s", tmp);
      40  	if (open(tmp, O_WRONLY) != 1)
      41  		perror_msg_and_fail("open: %s", tmp);
      42  	if (unlink(tmp))
      43  		perror_msg_and_fail("unlink: %s", tmp);
      44  
      45  	static const char w0_c[] = "012";
      46  	const char *w0_d = hexdump_strdup(w0_c);
      47  	void *w0 = tail_memdup(w0_c, LENGTH_OF(w0_c));
      48  
      49  	static const char w1_c[] = "34567";
      50  	const char *w1_d = hexdump_strdup(w1_c);
      51  	void *w1 = tail_memdup(w1_c, LENGTH_OF(w1_c));
      52  
      53  	static const char w2_c[] = "89abcde";
      54  	const char *w2_d = hexdump_strdup(w2_c);
      55  	void *w2 = tail_memdup(w2_c, LENGTH_OF(w2_c));
      56  
      57  	long rc;
      58  
      59  	static const char r0_c[] = "01234567";
      60  	const char *r0_d = hexdump_strdup(r0_c);
      61  	static const char r1_c[] = "89abcde";
      62  	const char *r1_d = hexdump_strdup(r1_c);
      63  
      64  	const struct iovec w_iov_[] = {
      65  		{
      66  			.iov_base = w0,
      67  			.iov_len = LENGTH_OF(w0_c)
      68  		}, {
      69  			.iov_base = w1,
      70  			.iov_len = LENGTH_OF(w1_c)
      71  		}, {
      72  			.iov_base = w2,
      73  			.iov_len = LENGTH_OF(w2_c)
      74  		}
      75  	};
      76  	const struct iovec *w_iov = tail_memdup(w_iov_, sizeof(w_iov_));
      77  
      78  	rc = pw(1, w_iov, 0, 0);
      79  	if (rc)
      80  		perror_msg_and_fail("pwritev2: expected 0, returned %ld", rc);
      81  	tprintf("pwritev2(1, [], 0, 0, 0) = 0\n");
      82  
      83  	rc = pw(1, w_iov + ARRAY_SIZE(w_iov_) - 1, 2, 0);
      84  	tprintf("pwritev2(1, [{iov_base=\"%s\", iov_len=%u}, ... /* %p */], 2, 0, 0)"
      85  		" = %ld %s (%m)\n",
      86  		w2_c, LENGTH_OF(w2_c), w_iov + ARRAY_SIZE(w_iov_),
      87  		rc, errno2name());
      88  
      89  	const unsigned int w_len =
      90  		LENGTH_OF(w0_c) + LENGTH_OF(w1_c) + LENGTH_OF(w2_c);
      91  
      92  	rc = pw(1, w_iov, ARRAY_SIZE(w_iov_), 0);
      93  	if (rc != (int) w_len)
      94  		perror_msg_and_fail("pwritev2: expected %u, returned %ld",
      95  				    w_len, rc);
      96  	close(1);
      97  	tprintf("pwritev2(1, [{iov_base=\"%s\", iov_len=%u}"
      98  		", {iov_base=\"%s\", iov_len=%u}"
      99  		", {iov_base=\"%s\", iov_len=%u}], %u, 0, 0) = %u\n"
     100  		" * %u bytes in buffer 0\n"
     101  		" | 00000 %-49s  %-16s |\n"
     102  		" * %u bytes in buffer 1\n"
     103  		" | 00000 %-49s  %-16s |\n"
     104  		" * %u bytes in buffer 2\n"
     105  		" | 00000 %-49s  %-16s |\n",
     106  		w0_c, LENGTH_OF(w0_c), w1_c, LENGTH_OF(w1_c),
     107  		w2_c, LENGTH_OF(w2_c), (unsigned int) ARRAY_SIZE(w_iov_), w_len,
     108  		LENGTH_OF(w0_c), w0_d, w0_c,
     109  		LENGTH_OF(w1_c), w1_d, w1_c, LENGTH_OF(w2_c), w2_d, w2_c);
     110  
     111  	const unsigned int r_len = (w_len + 1) / 2;
     112  	void *r0 = tail_alloc(r_len);
     113  	const struct iovec r0_iov_[] = {
     114  		{
     115  			.iov_base = r0,
     116  			.iov_len = r_len
     117  		}
     118  	};
     119  	const struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_));
     120  
     121  	rc = pr(0, r_iov, ARRAY_SIZE(r0_iov_), 0);
     122  	if (rc != (int) r_len)
     123  		perror_msg_and_fail("preadv2: expected %u, returned %ld",
     124  				    r_len, rc);
     125  	tprintf("preadv2(0, [{iov_base=\"%s\", iov_len=%u}], %u, 0, 0) = %u\n"
     126  		" * %u bytes in buffer 0\n"
     127  		" | 00000 %-49s  %-16s |\n",
     128  		r0_c, r_len, (unsigned int) ARRAY_SIZE(r0_iov_),
     129  		r_len, r_len, r0_d, r0_c);
     130  
     131  	void *r1 = tail_alloc(r_len);
     132  	void *r2 = tail_alloc(w_len);
     133  	const struct iovec r1_iov_[] = {
     134  		{
     135  			.iov_base = r1,
     136  			.iov_len = r_len
     137  		},
     138  		{
     139  			.iov_base = r2,
     140  			.iov_len = w_len
     141  		}
     142  	};
     143  	r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_));
     144  
     145  	rc = pr(0, r_iov, ARRAY_SIZE(r1_iov_), r_len);
     146  	if (rc != (int) w_len - (int) r_len)
     147  		perror_msg_and_fail("preadv2: expected %d, returned %ld",
     148  				    (int) w_len - r_len, rc);
     149  	tprintf("preadv2(0, [{iov_base=\"%s\", iov_len=%u}"
     150  		", {iov_base=\"\", iov_len=%u}], %u, %u, 0) = %u\n"
     151  		" * %u bytes in buffer 0\n"
     152  		" | 00000 %-49s  %-16s |\n",
     153  		r1_c, r_len, w_len, (unsigned int) ARRAY_SIZE(r1_iov_),
     154  		r_len, w_len - r_len,
     155  		w_len - r_len, r1_d, r1_c);
     156  	close(0);
     157  }
     158  
     159  int
     160  main(void)
     161  {
     162  	const kernel_ulong_t vlen = (kernel_ulong_t) 0xfac1fed2dad3bef4ULL;
     163  	const unsigned long long pos = 0x7ac5fed6dad7bef8;
     164  	const kernel_ulong_t pos_l = (kernel_ulong_t) pos;
     165  	long rc;
     166  	bool skip_dumpio_test = false;
     167  
     168  	tprintf("%s", "");
     169  
     170  #if defined __x86_64__ && defined __ILP32__
     171  	/*
     172  	 * x32 is the only architecture where preadv2 takes 5 arguments,
     173  	 * see preadv64v2 in kernel sources.
     174  	 */
     175  	rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, 1);
     176  #else
     177  	const kernel_ulong_t pos_h =
     178  		(sizeof(pos_l) == sizeof(pos)) ?
     179  		(kernel_ulong_t) 0xbadc0deddeadbeefULL :
     180  		(kernel_ulong_t) (pos >> 32);
     181  	rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, pos_h, 1);
     182  #endif
     183  	if (rc != -1)
     184  		error_msg_and_fail("preadv2: expected -1, returned %ld", rc);
     185  	switch (errno) {
     186  		case ENOSYS:
     187  			skip_dumpio_test = true;
     188  			break;
     189  		case EBADF:
     190  			break;
     191  		default:
     192  			perror_msg_and_fail("preadv2");
     193  	}
     194  	tprintf("preadv2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n",
     195  		(unsigned long) vlen, pos, sprintrc(rc));
     196  
     197  #if defined __x86_64__ && defined __ILP32__
     198  	/*
     199  	 * x32 is the only architecture where pwritev2 takes 5 arguments,
     200  	 * see pwritev64v2 in kernel sources.
     201  	 */
     202  	rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, 1);
     203  #else
     204  	rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, pos_h, 1);
     205  #endif
     206  	if (rc != -1)
     207  		error_msg_and_fail("pwritev2: expected -1, returned %ld", rc);
     208  	switch (errno) {
     209  		case ENOSYS:
     210  			skip_dumpio_test = true;
     211  			break;
     212  		case EBADF:
     213  			break;
     214  		default:
     215  			perror_msg_and_fail("pwritev2");
     216  	}
     217  	tprintf("pwritev2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n",
     218  		(unsigned long) vlen, pos, sprintrc(rc));
     219  
     220  	if (!skip_dumpio_test)
     221  		dumpio();
     222  
     223  	tprintf("%s\n", "+++ exited with 0 +++");
     224  	return 0;
     225  }