tools/nolibc: Fix build of stdio.h due to header ordering
[linux-block.git] / tools / testing / selftests / nolibc / nolibc-test.c
CommitLineData
362aecb2
WT
1// SPDX-License-Identifier: GPL-2.0
2
1da02f51
WT
3#define _GNU_SOURCE
4
362aecb2
WT
5/* platform-specific include files coming from the compiler */
6#include <limits.h>
7
8/* libc-specific include files
1da02f51 9 * The program may be built in 3 ways:
362aecb2 10 * $(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined
1da02f51
WT
11 * $(CC) -nostdlib -I/path/to/nolibc/sysroot => _NOLIBC_* guards are present
12 * $(CC) with default libc => NOLIBC* never defined
362aecb2
WT
13 */
14#ifndef NOLIBC
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
1da02f51
WT
18#ifndef _NOLIBC_STDIO_H
19/* standard libcs need more includes */
20#include <linux/reboot.h>
21#include <sys/io.h>
22#include <sys/ioctl.h>
69f2cd9f 23#include <sys/mman.h>
1da02f51
WT
24#include <sys/mount.h>
25#include <sys/reboot.h>
26#include <sys/stat.h>
27#include <sys/syscall.h>
28#include <sys/sysmacros.h>
29#include <sys/time.h>
30#include <sys/wait.h>
31#include <dirent.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <poll.h>
35#include <sched.h>
36#include <signal.h>
37#include <stdarg.h>
2df07fc5
WT
38#include <stddef.h>
39#include <stdint.h>
1da02f51
WT
40#include <unistd.h>
41#endif
362aecb2
WT
42#endif
43
44/* will be used by nolibc by getenv() */
45char **environ;
46
23da7bc9
WT
47/* definition of a series of tests */
48struct test {
49 const char *name; // test name
50 int (*func)(int min, int max); // handler
51};
52
1da02f51
WT
53#ifndef _NOLIBC_STDLIB_H
54char *itoa(int i)
55{
56 static char buf[12];
57 int ret;
58
59 ret = snprintf(buf, sizeof(buf), "%d", i);
60 return (ret >= 0 && ret < sizeof(buf)) ? buf : "#err";
61}
62#endif
63
362aecb2
WT
64#define CASE_ERR(err) \
65 case err: return #err
66
67/* returns the error name (e.g. "ENOENT") for common errors, "SUCCESS" for 0,
68 * or the decimal value for less common ones.
69 */
70const char *errorname(int err)
71{
72 switch (err) {
73 case 0: return "SUCCESS";
74 CASE_ERR(EPERM);
75 CASE_ERR(ENOENT);
76 CASE_ERR(ESRCH);
77 CASE_ERR(EINTR);
78 CASE_ERR(EIO);
79 CASE_ERR(ENXIO);
80 CASE_ERR(E2BIG);
81 CASE_ERR(ENOEXEC);
82 CASE_ERR(EBADF);
83 CASE_ERR(ECHILD);
84 CASE_ERR(EAGAIN);
85 CASE_ERR(ENOMEM);
86 CASE_ERR(EACCES);
87 CASE_ERR(EFAULT);
88 CASE_ERR(ENOTBLK);
89 CASE_ERR(EBUSY);
90 CASE_ERR(EEXIST);
91 CASE_ERR(EXDEV);
92 CASE_ERR(ENODEV);
93 CASE_ERR(ENOTDIR);
94 CASE_ERR(EISDIR);
95 CASE_ERR(EINVAL);
96 CASE_ERR(ENFILE);
97 CASE_ERR(EMFILE);
98 CASE_ERR(ENOTTY);
99 CASE_ERR(ETXTBSY);
100 CASE_ERR(EFBIG);
101 CASE_ERR(ENOSPC);
102 CASE_ERR(ESPIPE);
103 CASE_ERR(EROFS);
104 CASE_ERR(EMLINK);
105 CASE_ERR(EPIPE);
106 CASE_ERR(EDOM);
107 CASE_ERR(ERANGE);
108 CASE_ERR(ENOSYS);
109 default:
110 return itoa(err);
111 }
112}
113
114static int pad_spc(int llen, int cnt, const char *fmt, ...)
115{
116 va_list args;
117 int len;
118 int ret;
119
120 for (len = 0; len < cnt - llen; len++)
121 putchar(' ');
122
123 va_start(args, fmt);
124 ret = vfprintf(stdout, fmt, args);
125 va_end(args);
126 return ret < 0 ? ret : ret + len;
127}
128
129/* The tests below are intended to be used by the macroes, which evaluate
130 * expression <expr>, print the status to stdout, and update the "ret"
131 * variable to count failures. The functions themselves return the number
132 * of failures, thus either 0 or 1.
133 */
134
135#define EXPECT_ZR(cond, expr) \
a0994fb9 136 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0)
362aecb2
WT
137
138static int expect_zr(int expr, int llen)
139{
140 int ret = !(expr == 0);
141
142 llen += printf(" = %d ", expr);
a0994fb9 143 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
144 return ret;
145}
146
147
148#define EXPECT_NZ(cond, expr, val) \
a0994fb9 149 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0)
362aecb2
WT
150
151static int expect_nz(int expr, int llen)
152{
153 int ret = !(expr != 0);
154
155 llen += printf(" = %d ", expr);
a0994fb9 156 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
157 return ret;
158}
159
160
161#define EXPECT_EQ(cond, expr, val) \
a0994fb9 162 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0)
362aecb2 163
a0994fb9 164static int expect_eq(uint64_t expr, int llen, uint64_t val)
362aecb2
WT
165{
166 int ret = !(expr == val);
167
a0994fb9
VD
168 llen += printf(" = %lld ", expr);
169 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
170 return ret;
171}
172
173
174#define EXPECT_NE(cond, expr, val) \
a0994fb9 175 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0)
362aecb2
WT
176
177static int expect_ne(int expr, int llen, int val)
178{
179 int ret = !(expr != val);
180
181 llen += printf(" = %d ", expr);
a0994fb9 182 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
183 return ret;
184}
185
186
187#define EXPECT_GE(cond, expr, val) \
a0994fb9 188 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0)
362aecb2
WT
189
190static int expect_ge(int expr, int llen, int val)
191{
192 int ret = !(expr >= val);
193
194 llen += printf(" = %d ", expr);
a0994fb9 195 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
196 return ret;
197}
198
199
200#define EXPECT_GT(cond, expr, val) \
a0994fb9 201 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0)
362aecb2
WT
202
203static int expect_gt(int expr, int llen, int val)
204{
205 int ret = !(expr > val);
206
207 llen += printf(" = %d ", expr);
a0994fb9 208 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
209 return ret;
210}
211
212
213#define EXPECT_LE(cond, expr, val) \
a0994fb9 214 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0)
362aecb2
WT
215
216static int expect_le(int expr, int llen, int val)
217{
218 int ret = !(expr <= val);
219
220 llen += printf(" = %d ", expr);
a0994fb9 221 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
222 return ret;
223}
224
225
226#define EXPECT_LT(cond, expr, val) \
a0994fb9 227 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0)
362aecb2
WT
228
229static int expect_lt(int expr, int llen, int val)
230{
231 int ret = !(expr < val);
232
233 llen += printf(" = %d ", expr);
a0994fb9 234 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
362aecb2
WT
235 return ret;
236}
237
238
239#define EXPECT_SYSZR(cond, expr) \
a0994fb9 240 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0)
362aecb2
WT
241
242static int expect_syszr(int expr, int llen)
243{
244 int ret = 0;
245
246 if (expr) {
247 ret = 1;
248 llen += printf(" = %d %s ", expr, errorname(errno));
a0994fb9 249 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2
WT
250 } else {
251 llen += printf(" = %d ", expr);
a0994fb9 252 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
253 }
254 return ret;
255}
256
257
258#define EXPECT_SYSEQ(cond, expr, val) \
a0994fb9 259 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0)
362aecb2
WT
260
261static int expect_syseq(int expr, int llen, int val)
262{
263 int ret = 0;
264
265 if (expr != val) {
266 ret = 1;
267 llen += printf(" = %d %s ", expr, errorname(errno));
a0994fb9 268 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2
WT
269 } else {
270 llen += printf(" = %d ", expr);
a0994fb9 271 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
272 }
273 return ret;
274}
275
276
277#define EXPECT_SYSNE(cond, expr, val) \
a0994fb9 278 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0)
362aecb2
WT
279
280static int expect_sysne(int expr, int llen, int val)
281{
282 int ret = 0;
283
284 if (expr == val) {
285 ret = 1;
286 llen += printf(" = %d %s ", expr, errorname(errno));
a0994fb9 287 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2
WT
288 } else {
289 llen += printf(" = %d ", expr);
a0994fb9 290 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
291 }
292 return ret;
293}
294
295
296#define EXPECT_SYSER(cond, expr, expret, experr) \
a0994fb9 297 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0)
362aecb2
WT
298
299static int expect_syserr(int expr, int expret, int experr, int llen)
300{
301 int ret = 0;
302 int _errno = errno;
303
304 llen += printf(" = %d %s ", expr, errorname(_errno));
305 if (expr != expret || _errno != experr) {
306 ret = 1;
307 llen += printf(" != (%d %s) ", expret, errorname(experr));
a0994fb9 308 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 309 } else {
a0994fb9 310 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
311 }
312 return ret;
313}
314
315
316#define EXPECT_PTRZR(cond, expr) \
a0994fb9 317 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0)
362aecb2
WT
318
319static int expect_ptrzr(const void *expr, int llen)
320{
321 int ret = 0;
322
323 llen += printf(" = <%p> ", expr);
324 if (expr) {
325 ret = 1;
a0994fb9 326 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 327 } else {
a0994fb9 328 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
329 }
330 return ret;
331}
332
333
334#define EXPECT_PTRNZ(cond, expr) \
a0994fb9 335 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0)
362aecb2
WT
336
337static int expect_ptrnz(const void *expr, int llen)
338{
339 int ret = 0;
340
341 llen += printf(" = <%p> ", expr);
342 if (!expr) {
343 ret = 1;
a0994fb9 344 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 345 } else {
a0994fb9 346 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
347 }
348 return ret;
349}
350
351
352#define EXPECT_STRZR(cond, expr) \
a0994fb9 353 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0)
362aecb2
WT
354
355static int expect_strzr(const char *expr, int llen)
356{
357 int ret = 0;
358
359 llen += printf(" = <%s> ", expr);
360 if (expr) {
361 ret = 1;
a0994fb9 362 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 363 } else {
a0994fb9 364 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
365 }
366 return ret;
367}
368
369
370#define EXPECT_STRNZ(cond, expr) \
a0994fb9 371 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0)
362aecb2
WT
372
373static int expect_strnz(const char *expr, int llen)
374{
375 int ret = 0;
376
377 llen += printf(" = <%s> ", expr);
378 if (!expr) {
379 ret = 1;
a0994fb9 380 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 381 } else {
a0994fb9 382 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
383 }
384 return ret;
385}
386
387
388#define EXPECT_STREQ(cond, expr, cmp) \
a0994fb9 389 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0)
362aecb2
WT
390
391static int expect_streq(const char *expr, int llen, const char *cmp)
392{
393 int ret = 0;
394
395 llen += printf(" = <%s> ", expr);
396 if (strcmp(expr, cmp) != 0) {
397 ret = 1;
a0994fb9 398 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 399 } else {
a0994fb9 400 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
401 }
402 return ret;
403}
404
405
406#define EXPECT_STRNE(cond, expr, cmp) \
a0994fb9 407 do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0)
362aecb2
WT
408
409static int expect_strne(const char *expr, int llen, const char *cmp)
410{
411 int ret = 0;
412
413 llen += printf(" = <%s> ", expr);
414 if (strcmp(expr, cmp) == 0) {
415 ret = 1;
a0994fb9 416 llen += pad_spc(llen, 64, "[FAIL]\n");
362aecb2 417 } else {
a0994fb9 418 llen += pad_spc(llen, 64, " [OK]\n");
362aecb2
WT
419 }
420 return ret;
421}
422
23da7bc9 423
362aecb2
WT
424/* declare tests based on line numbers. There must be exactly one test per line. */
425#define CASE_TEST(name) \
426 case __LINE__: llen += printf("%d %s", test, #name);
427
428
b4844fa0
WT
429/* used by some syscall tests below */
430int test_getdents64(const char *dir)
431{
432 char buffer[4096];
433 int fd, ret;
434 int err;
435
436 ret = fd = open(dir, O_RDONLY | O_DIRECTORY, 0);
437 if (ret < 0)
438 return ret;
439
440 ret = getdents64(fd, (void *)buffer, sizeof(buffer));
441 err = errno;
442 close(fd);
443
444 errno = err;
445 return ret;
446}
447
a290296a
AF
448static int test_getpagesize(void)
449{
450 long x = getpagesize();
451 int c;
452
453 if (x < 0)
454 return x;
455
456#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
457 /*
458 * x86 family is always 4K page.
459 */
460 c = (x == 4096);
461#elif defined(__aarch64__)
462 /*
463 * Linux aarch64 supports three values of page size: 4K, 16K, and 64K
464 * which are selected at kernel compilation time.
465 */
466 c = (x == 4096 || x == (16 * 1024) || x == (64 * 1024));
467#else
468 /*
469 * Assuming other architectures must have at least 4K page.
470 */
471 c = (x >= 4096);
472#endif
473
474 return !c;
475}
476
b4844fa0
WT
477/* Run syscall tests between IDs <min> and <max>.
478 * Return 0 on success, non-zero on failure.
479 */
480int run_syscall(int min, int max)
481{
482 struct stat stat_buf;
3e2d337b 483 int euid0;
7172f1c6 484 int proc;
b4844fa0
WT
485 int test;
486 int tmp;
487 int ret = 0;
488 void *p1, *p2;
489
7172f1c6
WT
490 /* <proc> indicates whether or not /proc is mounted */
491 proc = stat("/proc", &stat_buf) == 0;
492
3e2d337b
WT
493 /* this will be used to skip certain tests that can't be run unprivileged */
494 euid0 = geteuid() == 0;
495
b4844fa0
WT
496 for (test = min; test >= 0 && test <= max; test++) {
497 int llen = 0; // line length
498
499 /* avoid leaving empty lines below, this will insert holes into
500 * test numbers.
501 */
502 switch (test + __LINE__ + 1) {
503 CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break;
504 CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break;
1da02f51 505#ifdef NOLIBC
b4844fa0 506 CASE_TEST(gettid); EXPECT_SYSNE(1, gettid(), -1); break;
1da02f51 507#endif
b4844fa0
WT
508 CASE_TEST(getpgid_self); EXPECT_SYSNE(1, getpgid(0), -1); break;
509 CASE_TEST(getpgid_bad); EXPECT_SYSER(1, getpgid(-1), -1, ESRCH); break;
510 CASE_TEST(kill_0); EXPECT_SYSZR(1, kill(getpid(), 0)); break;
511 CASE_TEST(kill_CONT); EXPECT_SYSZR(1, kill(getpid(), 0)); break;
512 CASE_TEST(kill_BADPID); EXPECT_SYSER(1, kill(INT_MAX, 0), -1, ESRCH); break;
513 CASE_TEST(sbrk); if ((p1 = p2 = sbrk(4096)) != (void *)-1) p2 = sbrk(-4096); EXPECT_SYSZR(1, (p2 == (void *)-1) || p2 == p1); break;
514 CASE_TEST(brk); EXPECT_SYSZR(1, brk(sbrk(0))); break;
515 CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break;
516 CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break;
517 CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break;
7172f1c6
WT
518 CASE_TEST(chmod_net); EXPECT_SYSZR(proc, chmod("/proc/self/net", 0555)); break;
519 CASE_TEST(chmod_self); EXPECT_SYSER(proc, chmod("/proc/self", 0555), -1, EPERM); break;
520 CASE_TEST(chown_self); EXPECT_SYSER(proc, chown("/proc/self", 0, 0), -1, EPERM); break;
3e2d337b 521 CASE_TEST(chroot_root); EXPECT_SYSZR(euid0, chroot("/")); break;
b4844fa0 522 CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break;
7172f1c6 523 CASE_TEST(chroot_exe); EXPECT_SYSER(proc, chroot("/proc/self/exe"), -1, ENOTDIR); break;
b4844fa0
WT
524 CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break;
525 CASE_TEST(close_dup); EXPECT_SYSZR(1, close(dup(0))); break;
526 CASE_TEST(dup_0); tmp = dup(0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
527 CASE_TEST(dup_m1); tmp = dup(-1); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
528 CASE_TEST(dup2_0); tmp = dup2(0, 100); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
529 CASE_TEST(dup2_m1); tmp = dup2(-1, 100); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
530 CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
531 CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
532 CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
533 CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
534 CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
535 CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break;
1da02f51 536#ifdef NOLIBC
b4844fa0
WT
537 CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break;
538 CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
539 CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break;
1da02f51 540#endif
a290296a 541 CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;
b4844fa0
WT
542 CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
543 CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break;
544 CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
545 CASE_TEST(link_blah); EXPECT_SYSER(1, link("/proc/self/blah", "/blah"), -1, ENOENT); break;
3e2d337b 546 CASE_TEST(link_dir); EXPECT_SYSER(euid0, link("/", "/blah"), -1, EPERM); break;
7172f1c6 547 CASE_TEST(link_cross); EXPECT_SYSER(proc, link("/proc/self/net", "/blah"), -1, EXDEV); break;
b4844fa0
WT
548 CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break;
549 CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break;
550 CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break;
551 CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break;
552 CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break;
553 CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break;
554 CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break;
555 CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break;
556 CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break;
557 CASE_TEST(sched_yield); EXPECT_SYSZR(1, sched_yield()); break;
558 CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break;
559 CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break;
560 CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break;
561 CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break;
562 CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
563 CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
564 CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;
565 CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break;
566 CASE_TEST(wait_child); EXPECT_SYSER(1, wait(&tmp), -1, ECHILD); break;
567 CASE_TEST(waitpid_min); EXPECT_SYSER(1, waitpid(INT_MIN, &tmp, WNOHANG), -1, ESRCH); break;
568 CASE_TEST(waitpid_child); EXPECT_SYSER(1, waitpid(getpid(), &tmp, WNOHANG), -1, ECHILD); break;
569 CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break;
570 CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break;
571 case __LINE__:
572 return ret; /* must be last */
573 /* note: do not set any defaults so as to permit holes above */
574 }
575 }
576 return ret;
577}
578
95bc9894
WT
579int run_stdlib(int min, int max)
580{
581 int test;
582 int tmp;
583 int ret = 0;
584 void *p1, *p2;
585
586 for (test = min; test >= 0 && test <= max; test++) {
587 int llen = 0; // line length
588
589 /* avoid leaving empty lines below, this will insert holes into
590 * test numbers.
591 */
592 switch (test + __LINE__ + 1) {
593 CASE_TEST(getenv_TERM); EXPECT_STRNZ(1, getenv("TERM")); break;
594 CASE_TEST(getenv_blah); EXPECT_STRZR(1, getenv("blah")); break;
595 CASE_TEST(setcmp_blah_blah); EXPECT_EQ(1, strcmp("blah", "blah"), 0); break;
596 CASE_TEST(setcmp_blah_blah2); EXPECT_NE(1, strcmp("blah", "blah2"), 0); break;
597 CASE_TEST(setncmp_blah_blah); EXPECT_EQ(1, strncmp("blah", "blah", 10), 0); break;
598 CASE_TEST(setncmp_blah_blah4); EXPECT_EQ(1, strncmp("blah", "blah4", 4), 0); break;
599 CASE_TEST(setncmp_blah_blah5); EXPECT_NE(1, strncmp("blah", "blah5", 5), 0); break;
600 CASE_TEST(setncmp_blah_blah6); EXPECT_NE(1, strncmp("blah", "blah6", 6), 0); break;
601 CASE_TEST(strchr_foobar_o); EXPECT_STREQ(1, strchr("foobar", 'o'), "oobar"); break;
602 CASE_TEST(strchr_foobar_z); EXPECT_STRZR(1, strchr("foobar", 'z')); break;
603 CASE_TEST(strrchr_foobar_o); EXPECT_STREQ(1, strrchr("foobar", 'o'), "obar"); break;
604 CASE_TEST(strrchr_foobar_z); EXPECT_STRZR(1, strrchr("foobar", 'z')); break;
c80b5a0a
WT
605 CASE_TEST(memcmp_20_20); EXPECT_EQ(1, memcmp("aaa\x20", "aaa\x20", 4), 0); break;
606 CASE_TEST(memcmp_20_60); EXPECT_LT(1, memcmp("aaa\x20", "aaa\x60", 4), 0); break;
607 CASE_TEST(memcmp_60_20); EXPECT_GT(1, memcmp("aaa\x60", "aaa\x20", 4), 0); break;
608 CASE_TEST(memcmp_20_e0); EXPECT_LT(1, memcmp("aaa\x20", "aaa\xe0", 4), 0); break;
609 CASE_TEST(memcmp_e0_20); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x20", 4), 0); break;
610 CASE_TEST(memcmp_80_e0); EXPECT_LT(1, memcmp("aaa\x80", "aaa\xe0", 4), 0); break;
611 CASE_TEST(memcmp_e0_80); EXPECT_GT(1, memcmp("aaa\xe0", "aaa\x80", 4), 0); break;
d1209597
VD
612 CASE_TEST(limit_int8_max); EXPECT_EQ(1, INT8_MAX, (int8_t) 0x7f); break;
613 CASE_TEST(limit_int8_min); EXPECT_EQ(1, INT8_MIN, (int8_t) 0x80); break;
614 CASE_TEST(limit_uint8_max); EXPECT_EQ(1, UINT8_MAX, (uint8_t) 0xff); break;
615 CASE_TEST(limit_int16_max); EXPECT_EQ(1, INT16_MAX, (int16_t) 0x7fff); break;
616 CASE_TEST(limit_int16_min); EXPECT_EQ(1, INT16_MIN, (int16_t) 0x8000); break;
617 CASE_TEST(limit_uint16_max); EXPECT_EQ(1, UINT16_MAX, (uint16_t) 0xffff); break;
618 CASE_TEST(limit_int32_max); EXPECT_EQ(1, INT32_MAX, (int32_t) 0x7fffffff); break;
619 CASE_TEST(limit_int32_min); EXPECT_EQ(1, INT32_MIN, (int32_t) 0x80000000); break;
620 CASE_TEST(limit_uint32_max); EXPECT_EQ(1, UINT32_MAX, (uint32_t) 0xffffffff); break;
621 CASE_TEST(limit_int64_max); EXPECT_EQ(1, INT64_MAX, (int64_t) 0x7fffffffffffffff); break;
622 CASE_TEST(limit_int64_min); EXPECT_EQ(1, INT64_MIN, (int64_t) 0x8000000000000000); break;
623 CASE_TEST(limit_uint64_max); EXPECT_EQ(1, UINT64_MAX, (uint64_t) 0xffffffffffffffff); break;
624 CASE_TEST(limit_int_least8_max); EXPECT_EQ(1, INT_LEAST8_MAX, (int_least8_t) 0x7f); break;
625 CASE_TEST(limit_int_least8_min); EXPECT_EQ(1, INT_LEAST8_MIN, (int_least8_t) 0x80); break;
626 CASE_TEST(limit_uint_least8_max); EXPECT_EQ(1, UINT_LEAST8_MAX, (uint_least8_t) 0xff); break;
627 CASE_TEST(limit_int_least16_max); EXPECT_EQ(1, INT_LEAST16_MAX, (int_least16_t) 0x7fff); break;
628 CASE_TEST(limit_int_least16_min); EXPECT_EQ(1, INT_LEAST16_MIN, (int_least16_t) 0x8000); break;
629 CASE_TEST(limit_uint_least16_max); EXPECT_EQ(1, UINT_LEAST16_MAX, (uint_least16_t) 0xffff); break;
630 CASE_TEST(limit_int_least32_max); EXPECT_EQ(1, INT_LEAST32_MAX, (int_least32_t) 0x7fffffff); break;
631 CASE_TEST(limit_int_least32_min); EXPECT_EQ(1, INT_LEAST32_MIN, (int_least32_t) 0x80000000); break;
632 CASE_TEST(limit_uint_least32_max); EXPECT_EQ(1, UINT_LEAST32_MAX, (uint_least32_t) 0xffffffffU); break;
633 CASE_TEST(limit_int_least64_min); EXPECT_EQ(1, INT_LEAST64_MIN, (int_least64_t) 0x8000000000000000LL); break;
634 CASE_TEST(limit_int_least64_max); EXPECT_EQ(1, INT_LEAST64_MAX, (int_least64_t) 0x7fffffffffffffffLL); break;
635 CASE_TEST(limit_uint_least64_max); EXPECT_EQ(1, UINT_LEAST64_MAX, (uint_least64_t) 0xffffffffffffffffULL); break;
636 CASE_TEST(limit_int_fast8_max); EXPECT_EQ(1, INT_FAST8_MAX, (int_fast8_t) 0x7f); break;
637 CASE_TEST(limit_int_fast8_min); EXPECT_EQ(1, INT_FAST8_MIN, (int_fast8_t) 0x80); break;
638 CASE_TEST(limit_uint_fast8_max); EXPECT_EQ(1, UINT_FAST8_MAX, (uint_fast8_t) 0xff); break;
639 CASE_TEST(limit_int_fast16_min); EXPECT_EQ(1, INT_FAST16_MIN, (int_fast16_t) INTPTR_MIN); break;
640 CASE_TEST(limit_int_fast16_max); EXPECT_EQ(1, INT_FAST16_MAX, (int_fast16_t) INTPTR_MAX); break;
641 CASE_TEST(limit_uint_fast16_max); EXPECT_EQ(1, UINT_FAST16_MAX, (uint_fast16_t) UINTPTR_MAX); break;
642 CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break;
643 CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break;
644 CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break;
645 CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INTPTR_MIN); break;
646 CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INTPTR_MAX); break;
647 CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINTPTR_MAX); break;
648#if __SIZEOF_LONG__ == 8
649 CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break;
650 CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break;
651 CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffffffffffULL); break;
652 CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x8000000000000000LL); break;
653 CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffffffffffffLL); break;
654 CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffffffffffULL); break;
655#elif __SIZEOF_LONG__ == 4
656 CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x80000000); break;
657 CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffff); break;
658 CASE_TEST(limit_uintptr_max); EXPECT_EQ(1, UINTPTR_MAX, (uintptr_t) 0xffffffffU); break;
659 CASE_TEST(limit_ptrdiff_min); EXPECT_EQ(1, PTRDIFF_MIN, (ptrdiff_t) 0x80000000); break;
660 CASE_TEST(limit_ptrdiff_max); EXPECT_EQ(1, PTRDIFF_MAX, (ptrdiff_t) 0x7fffffff); break;
661 CASE_TEST(limit_size_max); EXPECT_EQ(1, SIZE_MAX, (size_t) 0xffffffffU); break;
662#else
663# warning "__SIZEOF_LONG__ is undefined"
664#endif /* __SIZEOF_LONG__ */
95bc9894
WT
665 case __LINE__:
666 return ret; /* must be last */
667 /* note: do not set any defaults so as to permit holes above */
668 }
669 }
670 return ret;
671}
672
69f2cd9f
TW
673#define EXPECT_VFPRINTF(c, expected, fmt, ...) \
674 ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__)
675
676static int expect_vfprintf(int llen, size_t c, const char *expected, const char *fmt, ...)
677{
678 int ret, fd, w, r;
679 char buf[100];
680 FILE *memfile;
681 va_list args;
682
683 fd = memfd_create("vfprintf", 0);
684 if (fd == -1) {
685 pad_spc(llen, 64, "[FAIL]\n");
686 return 1;
687 }
688
689 memfile = fdopen(fd, "w+");
690 if (!memfile) {
691 pad_spc(llen, 64, "[FAIL]\n");
692 return 1;
693 }
694
695 va_start(args, fmt);
696 w = vfprintf(memfile, fmt, args);
697 va_end(args);
698
699 if (w != c) {
700 llen += printf(" written(%d) != %d", w, (int) c);
701 pad_spc(llen, 64, "[FAIL]\n");
702 return 1;
703 }
704
705 fflush(memfile);
706 lseek(fd, 0, SEEK_SET);
707
708 r = read(fd, buf, sizeof(buf) - 1);
709 buf[r] = '\0';
710
711 fclose(memfile);
712
713 if (r != w) {
714 llen += printf(" written(%d) != read(%d)", w, r);
715 pad_spc(llen, 64, "[FAIL]\n");
716 return 1;
717 }
718
719 llen += printf(" \"%s\" = \"%s\"", expected, buf);
720 ret = strncmp(expected, buf, c);
721
722 pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
723 return ret;
724}
725
726static int run_vfprintf(int min, int max)
727{
728 int test;
729 int tmp;
730 int ret = 0;
731 void *p1, *p2;
732
733 for (test = min; test >= 0 && test <= max; test++) {
734 int llen = 0; // line length
735
736 /* avoid leaving empty lines below, this will insert holes into
737 * test numbers.
738 */
739 switch (test + __LINE__ + 1) {
740 CASE_TEST(empty); EXPECT_VFPRINTF(0, "", ""); break;
741 CASE_TEST(simple); EXPECT_VFPRINTF(3, "foo", "foo"); break;
742 CASE_TEST(string); EXPECT_VFPRINTF(3, "foo", "%s", "foo"); break;
743 CASE_TEST(number); EXPECT_VFPRINTF(4, "1234", "%d", 1234); break;
744 CASE_TEST(negnumber); EXPECT_VFPRINTF(5, "-1234", "%d", -1234); break;
745 CASE_TEST(unsigned); EXPECT_VFPRINTF(5, "12345", "%u", 12345); break;
746 CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break;
747 CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break;
748 CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break;
749 case __LINE__:
750 return ret; /* must be last */
751 /* note: do not set any defaults so as to permit holes above */
752 }
753 }
754 return ret;
755}
756
97357168
TW
757static int smash_stack(void)
758{
759 char buf[100];
e7654c3f 760 volatile char *ptr = buf;
aa662d12 761 size_t i;
97357168 762
aa662d12 763 for (i = 0; i < 200; i++)
e7654c3f 764 ptr[i] = 'P';
97357168
TW
765
766 return 1;
767}
768
769static int run_protection(int min, int max)
770{
771 pid_t pid;
772 int llen = 0, status;
773
774 llen += printf("0 -fstackprotector ");
775
776#if !defined(NOLIBC_STACKPROTECTOR)
777 llen += printf("not supported");
778 pad_spc(llen, 64, "[SKIPPED]\n");
779 return 0;
780#endif
781
782 pid = -1;
783 pid = fork();
784
785 switch (pid) {
786 case -1:
787 llen += printf("fork()");
788 pad_spc(llen, 64, "[FAIL]\n");
789 return 1;
790
791 case 0:
792 close(STDOUT_FILENO);
793 close(STDERR_FILENO);
794
795 smash_stack();
796 return 1;
797
798 default:
799 pid = waitpid(pid, &status, 0);
800
801 if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) {
802 llen += printf("waitpid()");
803 pad_spc(llen, 64, "[FAIL]\n");
804 return 1;
805 }
806 pad_spc(llen, 64, " [OK]\n");
807 return 0;
808 }
809}
810
1a5454f6
WT
811/* prepare what needs to be prepared for pid 1 (stdio, /dev, /proc, etc) */
812int prepare(void)
813{
814 struct stat stat_buf;
815
816 /* It's possible that /dev doesn't even exist or was not mounted, so
817 * we'll try to create it, mount it, or create minimal entries into it.
818 * We want at least /dev/null and /dev/console.
819 */
820 if (stat("/dev/.", &stat_buf) == 0 || mkdir("/dev", 0755) == 0) {
821 if (stat("/dev/console", &stat_buf) != 0 ||
822 stat("/dev/null", &stat_buf) != 0) {
823 /* try devtmpfs first, otherwise fall back to manual creation */
824 if (mount("/dev", "/dev", "devtmpfs", 0, 0) != 0) {
825 mknod("/dev/console", 0600 | S_IFCHR, makedev(5, 1));
826 mknod("/dev/null", 0666 | S_IFCHR, makedev(1, 3));
827 }
828 }
829 }
830
831 /* If no /dev/console was found before calling init, stdio is closed so
832 * we need to reopen it from /dev/console. If it failed above, it will
833 * still fail here and we cannot emit a message anyway.
834 */
835 if (close(dup(1)) == -1) {
836 int fd = open("/dev/console", O_RDWR);
837
838 if (fd >= 0) {
839 if (fd != 0)
840 dup2(fd, 0);
841 if (fd != 1)
842 dup2(fd, 1);
843 if (fd != 2)
844 dup2(fd, 2);
845 if (fd > 2)
846 close(fd);
847 puts("\nSuccessfully reopened /dev/console.");
848 }
849 }
850
851 /* try to mount /proc if not mounted. Silently fail otherwise */
852 if (stat("/proc/.", &stat_buf) == 0 || mkdir("/proc", 0755) == 0) {
853 if (stat("/proc/self", &stat_buf) != 0)
854 mount("/proc", "/proc", "proc", 0, 0);
855 }
856
857 return 0;
858}
b4844fa0 859
23da7bc9 860/* This is the definition of known test names, with their functions */
c4560bd8 861static const struct test test_names[] = {
23da7bc9 862 /* add new tests here */
97357168
TW
863 { .name = "syscall", .func = run_syscall },
864 { .name = "stdlib", .func = run_stdlib },
69f2cd9f 865 { .name = "vfprintf", .func = run_vfprintf },
97357168 866 { .name = "protection", .func = run_protection },
23da7bc9
WT
867 { 0 }
868};
869
362aecb2
WT
870int main(int argc, char **argv, char **envp)
871{
872 int min = 0;
873 int max = __INT_MAX__;
874 int ret = 0;
23da7bc9
WT
875 int err;
876 int idx;
877 char *test;
362aecb2
WT
878
879 environ = envp;
880
1a5454f6
WT
881 /* when called as init, it's possible that no console was opened, for
882 * example if no /dev file system was provided. We'll check that fd#1
883 * was opened, and if not we'll attempt to create and open /dev/console
884 * and /dev/null that we'll use for later tests.
885 */
886 if (getpid() == 1)
887 prepare();
888
23da7bc9
WT
889 /* the definition of a series of tests comes from either argv[1] or the
890 * "NOLIBC_TEST" environment variable. It's made of a comma-delimited
891 * series of test names and optional ranges:
892 * syscall:5-15[:.*],stdlib:8-10
893 */
894 test = argv[1];
895 if (!test)
896 test = getenv("NOLIBC_TEST");
897
898 if (test) {
899 char *comma, *colon, *dash, *value;
900
901 do {
902 comma = strchr(test, ',');
903 if (comma)
904 *(comma++) = '\0';
905
906 colon = strchr(test, ':');
907 if (colon)
908 *(colon++) = '\0';
909
910 for (idx = 0; test_names[idx].name; idx++) {
911 if (strcmp(test, test_names[idx].name) == 0)
912 break;
913 }
914
915 if (test_names[idx].name) {
916 /* The test was named, it will be called at least
917 * once. We may have an optional range at <colon>
918 * here, which defaults to the full range.
919 */
920 do {
921 min = 0; max = __INT_MAX__;
922 value = colon;
923 if (value && *value) {
924 colon = strchr(value, ':');
925 if (colon)
926 *(colon++) = '\0';
927
928 dash = strchr(value, '-');
929 if (dash)
930 *(dash++) = '\0';
931
932 /* support :val: :min-max: :min-: :-max: */
933 if (*value)
934 min = atoi(value);
935 if (!dash)
936 max = min;
937 else if (*dash)
938 max = atoi(dash);
939
940 value = colon;
941 }
942
943 /* now's time to call the test */
944 printf("Running test '%s'\n", test_names[idx].name);
945 err = test_names[idx].func(min, max);
946 ret += err;
947 printf("Errors during this test: %d\n\n", err);
948 } while (colon && *colon);
949 } else
950 printf("Ignoring unknown test name '%s'\n", test);
951
952 test = comma;
953 } while (test && *test);
954 } else {
955 /* no test mentioned, run everything */
956 for (idx = 0; test_names[idx].name; idx++) {
957 printf("Running test '%s'\n", test_names[idx].name);
958 err = test_names[idx].func(min, max);
959 ret += err;
960 printf("Errors during this test: %d\n\n", err);
961 }
962 }
963
362aecb2 964 printf("Total number of errors: %d\n", ret);
f49896d7
WT
965
966 if (getpid() == 1) {
967 /* we're running as init, there's no other process on the
968 * system, thus likely started from a VM for a quick check.
969 * Exiting will provoke a kernel panic that may be reported
970 * as an error by Qemu or the hypervisor, while stopping
971 * cleanly will often be reported as a success. This allows
972 * to use the output of this program for bisecting kernels.
973 */
974 printf("Leaving init with final status: %d\n", !!ret);
975 if (ret == 0)
976 reboot(LINUX_REBOOT_CMD_POWER_OFF);
aa73a86c
WT
977#if defined(__x86_64__)
978 /* QEMU started with "-device isa-debug-exit -no-reboot" will
979 * exit with status code 2N+1 when N is written to 0x501. We
980 * hard-code the syscall here as it's arch-dependent.
981 */
1da02f51 982#if defined(_NOLIBC_SYS_H)
aa73a86c 983 else if (my_syscall3(__NR_ioperm, 0x501, 1, 1) == 0)
1da02f51
WT
984#else
985 else if (ioperm(0x501, 1, 1) == 0)
986#endif
aa73a86c
WT
987 asm volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0));
988 /* if it does nothing, fall back to the regular panic */
989#endif
f49896d7
WT
990 }
991
362aecb2
WT
992 printf("Exiting with status %d\n", !!ret);
993 return !!ret;
994}