1 /*
2 * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/syscall.h>
42
43 #ifdef __NR_sendfile64
44
45 int
main(int ac,const char ** av)46 main(int ac, const char **av)
47 {
48 assert(ac == 2);
49
50 (void) close(0);
51 if (open("/dev/zero", O_RDONLY) != 0)
52 return 77;
53
54 int sv[2];
55 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
56 return 77;
57
58 int reg_in = open(av[1], O_RDONLY);
59 if (reg_in < 0)
60 return 77;
61
62 struct stat stb;
63 if (fstat(reg_in, &stb))
64 return 77;
65 const size_t blen = stb.st_size / 3;
66 const size_t alen = stb.st_size - blen;
67 assert(S_ISREG(stb.st_mode) && blen > 0);
68
69 const size_t page_len = sysconf(_SC_PAGESIZE);
70 if (!syscall(__NR_sendfile64, 0, 1, NULL, page_len) ||
71 EBADF != errno)
72 return 77;
73 printf("sendfile64(0, 1, NULL, %lu) = -1 EBADF (Bad file descriptor)\n",
74 (unsigned long) page_len);
75
76 void *p = mmap(NULL, page_len * 2, PROT_READ | PROT_WRITE,
77 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
78 if (MAP_FAILED == p || munmap(p + page_len, page_len))
79 return 77;
80
81 if (!syscall(__NR_sendfile64, 0, 1, p + page_len, page_len))
82 return 77;
83 printf("sendfile64(0, 1, %#lx, %lu) = -1 EFAULT (Bad address)\n",
84 (unsigned long) p + page_len, (unsigned long) page_len);
85
86 if (syscall(__NR_sendfile64, sv[1], reg_in, NULL, alen) != (long) alen)
87 return 77;
88 printf("sendfile64(%d, %d, NULL, %lu) = %lu\n",
89 sv[1], reg_in, (unsigned long) alen,
90 (unsigned long) alen);
91
92 uint64_t *p_off = p + page_len - sizeof(uint64_t);
93 if (syscall(__NR_sendfile64, sv[1], reg_in, p_off, alen) != (long) alen)
94 return 77;
95 printf("sendfile64(%d, %d, [0] => [%lu], %lu) = %lu\n",
96 sv[1], reg_in, (unsigned long) alen,
97 (unsigned long) alen, (unsigned long) alen);
98
99 if (syscall(__NR_sendfile64, sv[1], reg_in, p_off, stb.st_size + 1)
100 != (long) blen)
101 return 77;
102 printf("sendfile64(%d, %d, [%lu] => [%lu], %lu) = %lu\n",
103 sv[1], reg_in, (unsigned long) alen,
104 (unsigned long) stb.st_size,
105 (unsigned long) stb.st_size + 1,
106 (unsigned long) blen);
107
108 *p_off = 0xcafef00dfacefeed;
109 if (!syscall(__NR_sendfile64, sv[1], reg_in, p_off, 1))
110 return 77;
111 printf("sendfile64(%d, %d, [14627392582579060461], 1)"
112 " = -1 EINVAL (Invalid argument)\n",
113 sv[1], reg_in);
114
115 *p_off = 0xfacefeed;
116 if (syscall(__NR_sendfile64, sv[1], reg_in, p_off, 1))
117 return 77;
118 printf("sendfile64(%d, %d, [4207869677], 1) = 0\n",
119 sv[1], reg_in);
120
121 puts("+++ exited with 0 +++");
122 return 0;
123 }
124
125 #else
126
127 int
main(void)128 main(void)
129 {
130 return 77;
131 }
132
133 #endif
134