(root)/
strace-6.5/
tests/
qual_fault.c
       1  /*
       2   * Check that fault injection works properly.
       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  
      13  #include <assert.h>
      14  #include <errno.h>
      15  #include <fcntl.h>
      16  #include <limits.h>
      17  #include <stdio.h>
      18  #include <stdlib.h>
      19  #include <string.h>
      20  #include <unistd.h>
      21  #include <sys/stat.h>
      22  #include <sys/uio.h>
      23  #include <sys/wait.h>
      24  
      25  static int exp_fd;
      26  static int got_fd;
      27  static int out_fd;
      28  
      29  #define DEFAULT_ERRNO ENOSYS
      30  
      31  static const char *errstr;
      32  static int is_raw, err;
      33  
      34  static void
      35  invoke(int iter, int fail)
      36  {
      37  	static char buf[sizeof(int) * 3 + 3];
      38  	static int try;
      39  	const struct iovec io = {
      40  		.iov_base = buf,
      41  		.iov_len = sprintf(buf, "%d.", ++try)
      42  	};
      43  	int rc;
      44  
      45  	if (!fail) {
      46  		rc = write(exp_fd, io.iov_base, io.iov_len);
      47  		if (rc != (int) io.iov_len)
      48  			perror_msg_and_fail("iter %d: write", iter);
      49  	}
      50  
      51  	errno = 0;
      52  	rc = writev(got_fd, &io, 1);
      53  
      54  	if (fail) {
      55  		if (!(rc == -1 && errno == err))
      56  			perror_msg_and_fail("iter %d: expected errno %d"
      57  					    ", got rc == %d, errno == %d",
      58  					    iter, err, rc, errno);
      59  
      60  		if (is_raw)
      61  			tprintf("writev(%#x, %p, 0x1)"
      62  				" = -1 %s (%m) (INJECTED)\n",
      63  				got_fd, &io, errstr);
      64  		else
      65  			tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
      66  				" = -1 %s (%m) (INJECTED)\n",
      67  				got_fd, buf, (int) io.iov_len, errstr);
      68  	} else {
      69  		if (rc != (int) io.iov_len)
      70  			perror_msg_and_fail("iter %d: expected %d"
      71  					    ", got rc == %d, errno == %d",
      72  					    iter, (int) io.iov_len, rc, errno);
      73  
      74  		if (is_raw)
      75  			tprintf("writev(%#x, %p, 0x1) = %#x\n",
      76  				got_fd, &io, rc);
      77  		else
      78  			tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
      79  				" = %d\n",
      80  				got_fd, buf, (int) io.iov_len,
      81  				(int) io.iov_len);
      82  	}
      83  }
      84  
      85  static int
      86  open_file(const char *prefix, int proc)
      87  {
      88  	static const int open_flags = O_WRONLY | O_TRUNC | O_CREAT;
      89  	static char path[PATH_MAX + 1];
      90  
      91  	snprintf(path, sizeof(path), "%s.%d", prefix, proc);
      92  
      93  	int fd = open(path, open_flags, 0600);
      94  	if (fd < 0)
      95  		perror_msg_and_fail("open: %s", path);
      96  
      97  	return fd;
      98  }
      99  
     100  int
     101  main(int argc, char *argv[])
     102  {
     103  	assert(argc == 12);
     104  
     105  	is_raw = !strcmp("raw", argv[1]);
     106  
     107  	errstr = argv[2];
     108  	err = atoi(errstr);
     109  	assert(err >= 0);
     110  
     111  	if (!err) {
     112  		if (!*errstr)
     113  			err = DEFAULT_ERRNO;
     114  		else if (!strcasecmp(errstr, "EINVAL"))
     115  			err = EINVAL;
     116  		else
     117  			err = ENOSYS;
     118  	}
     119  
     120  	errno = err;
     121  	errstr = errno2name();
     122  
     123  	int first = atoi(argv[3]);
     124  	int last = atoi(argv[4]);
     125  	int step = atoi(argv[5]);
     126  	int iter = atoi(argv[6]);
     127  	int num_procs = atoi(argv[7]);
     128  	char *exp_prefix = argv[8];
     129  	char *got_prefix = argv[9];
     130  	char *out_prefix = argv[10];
     131  	char *pid_prefix = argv[11];
     132  
     133  	assert(first > 0);
     134  	assert(step >= 0);
     135  	assert(num_procs > 0);
     136  
     137  	for (int proc = 0; proc < num_procs; ++proc) {
     138  		int ret = fork();
     139  
     140  		if (ret < 0)
     141  			perror_msg_and_fail("fork");
     142  
     143  		if (ret > 0) {
     144  			int pidfd = open_file(pid_prefix, proc);
     145  
     146  			char pidstr[sizeof(ret) * 3];
     147  			int len = snprintf(pidstr, sizeof(pidstr), "%d", ret);
     148  			assert(len > 0 && len < (int) sizeof(pidstr));
     149  			assert(write(pidfd, pidstr, len) == len);
     150  
     151  			close(pidfd);
     152  
     153  			continue;
     154  		}
     155  
     156  		tprintf("%s", "");
     157  
     158  		exp_fd = open_file(exp_prefix, proc);
     159  		got_fd = open_file(got_prefix, proc);
     160  		out_fd = open_file(out_prefix, proc);
     161  
     162  		/* This magic forces tprintf to write where we want it. */
     163  		dup2(out_fd, 3);
     164  
     165  		for (int i = 1; i <= iter; ++i) {
     166  			int fail = 0;
     167  			if (last != 0) {
     168  				--first;
     169  				if (last != -1)
     170  					--last;
     171  				if (first == 0) {
     172  					fail = 1;
     173  					first = step;
     174  				}
     175  			}
     176  			invoke(i, fail);
     177  		}
     178  
     179  		tprintf("%s\n", "+++ exited with 0 +++");
     180  		return 0;
     181  	}
     182  
     183  	for (int proc = 0; proc < num_procs; ++proc) {
     184  		int status;
     185  		int ret = wait(&status);
     186  		if (ret <= 0)
     187  			perror_msg_and_fail("wait %d", proc);
     188  		if (status)
     189  			error_msg_and_fail("wait: pid=%d status=%d",
     190  					   ret, status);
     191  	}
     192  
     193  	return 0;
     194  }