linux-test.c (13798B)
1/* 2 * linux and CPU test 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19#define _GNU_SOURCE 20#include <stdarg.h> 21#include <stdlib.h> 22#include <stdio.h> 23#include <unistd.h> 24#include <fcntl.h> 25#include <inttypes.h> 26#include <string.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <sys/wait.h> 30#include <errno.h> 31#include <utime.h> 32#include <time.h> 33#include <sys/time.h> 34#include <sys/resource.h> 35#include <sys/uio.h> 36#include <sys/socket.h> 37#include <netinet/in.h> 38#include <arpa/inet.h> 39#include <sched.h> 40#include <dirent.h> 41#include <setjmp.h> 42#include <sys/shm.h> 43#include <assert.h> 44 45#define STACK_SIZE 16384 46 47static void error1(const char *filename, int line, const char *fmt, ...) 48{ 49 va_list ap; 50 va_start(ap, fmt); 51 fprintf(stderr, "%s:%d: ", filename, line); 52 vfprintf(stderr, fmt, ap); 53 fprintf(stderr, "\n"); 54 va_end(ap); 55 exit(1); 56} 57 58static int __chk_error(const char *filename, int line, int ret) 59{ 60 if (ret < 0) { 61 error1(filename, line, "%m (ret=%d, errno=%d/%s)", 62 ret, errno, strerror(errno)); 63 } 64 return ret; 65} 66 67#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) 68 69#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) 70 71/*******************************************************/ 72 73#define FILE_BUF_SIZE 300 74 75static void test_file(void) 76{ 77 int fd, i, len, ret; 78 uint8_t buf[FILE_BUF_SIZE]; 79 uint8_t buf2[FILE_BUF_SIZE]; 80 uint8_t buf3[FILE_BUF_SIZE]; 81 char cur_dir[1024]; 82 struct stat st; 83 struct utimbuf tbuf; 84 struct iovec vecs[2]; 85 DIR *dir; 86 struct dirent64 *de; 87 /* TODO: make common tempdir creation for tcg tests */ 88 char template[] = "/tmp/linux-test-XXXXXX"; 89 char *tmpdir = mkdtemp(template); 90 91 assert(tmpdir); 92 93 if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) 94 error("getcwd"); 95 96 chk_error(chdir(tmpdir)); 97 98 /* open/read/write/close/readv/writev/lseek */ 99 100 fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); 101 for(i=0;i < FILE_BUF_SIZE; i++) 102 buf[i] = i; 103 len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2)); 104 if (len != (FILE_BUF_SIZE / 2)) 105 error("write"); 106 vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2); 107 vecs[0].iov_len = 16; 108 vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16; 109 vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16; 110 len = chk_error(writev(fd, vecs, 2)); 111 if (len != (FILE_BUF_SIZE / 2)) 112 error("writev"); 113 chk_error(close(fd)); 114 115 chk_error(rename("file1", "file2")); 116 117 fd = chk_error(open("file2", O_RDONLY)); 118 119 len = chk_error(read(fd, buf2, FILE_BUF_SIZE)); 120 if (len != FILE_BUF_SIZE) 121 error("read"); 122 if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) 123 error("memcmp"); 124 125#define FOFFSET 16 126 ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); 127 if (ret != 16) 128 error("lseek"); 129 vecs[0].iov_base = buf3; 130 vecs[0].iov_len = 32; 131 vecs[1].iov_base = buf3 + 32; 132 vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32; 133 len = chk_error(readv(fd, vecs, 2)); 134 if (len != FILE_BUF_SIZE - FOFFSET) 135 error("readv"); 136 if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) 137 error("memcmp"); 138 139 chk_error(close(fd)); 140 141 /* access */ 142 chk_error(access("file2", R_OK)); 143 144 /* stat/chmod/utime/truncate */ 145 146 chk_error(chmod("file2", 0600)); 147 tbuf.actime = 1001; 148 tbuf.modtime = 1000; 149 chk_error(truncate("file2", 100)); 150 chk_error(utime("file2", &tbuf)); 151 chk_error(stat("file2", &st)); 152 if (st.st_size != 100) 153 error("stat size"); 154 if (!S_ISREG(st.st_mode)) 155 error("stat mode"); 156 if ((st.st_mode & 0777) != 0600) 157 error("stat mode2"); 158 if (st.st_atime != 1001 || 159 st.st_mtime != 1000) 160 error("stat time"); 161 162 chk_error(stat(tmpdir, &st)); 163 if (!S_ISDIR(st.st_mode)) 164 error("stat mode"); 165 166 /* fstat */ 167 fd = chk_error(open("file2", O_RDWR)); 168 chk_error(ftruncate(fd, 50)); 169 chk_error(fstat(fd, &st)); 170 chk_error(close(fd)); 171 172 if (st.st_size != 50) 173 error("stat size"); 174 if (!S_ISREG(st.st_mode)) 175 error("stat mode"); 176 177 /* symlink/lstat */ 178 chk_error(symlink("file2", "file3")); 179 chk_error(lstat("file3", &st)); 180 if (!S_ISLNK(st.st_mode)) 181 error("stat mode"); 182 183 /* getdents */ 184 dir = opendir(tmpdir); 185 if (!dir) 186 error("opendir"); 187 len = 0; 188 for(;;) { 189 de = readdir64(dir); 190 if (!de) 191 break; 192 if (strcmp(de->d_name, ".") != 0 && 193 strcmp(de->d_name, "..") != 0 && 194 strcmp(de->d_name, "file2") != 0 && 195 strcmp(de->d_name, "file3") != 0) 196 error("readdir"); 197 len++; 198 } 199 closedir(dir); 200 if (len != 4) 201 error("readdir"); 202 203 chk_error(unlink("file3")); 204 chk_error(unlink("file2")); 205 chk_error(chdir(cur_dir)); 206 chk_error(rmdir(tmpdir)); 207} 208 209static void test_fork(void) 210{ 211 int pid, status; 212 213 pid = chk_error(fork()); 214 if (pid == 0) { 215 /* child */ 216 sleep(2); 217 exit(2); 218 } 219 chk_error(waitpid(pid, &status, 0)); 220 if (!WIFEXITED(status) || WEXITSTATUS(status) != 2) 221 error("waitpid status=0x%x", status); 222} 223 224static void test_time(void) 225{ 226 struct timeval tv, tv2; 227 struct timespec ts, rem; 228 struct rusage rusg1, rusg2; 229 int ti, i; 230 231 chk_error(gettimeofday(&tv, NULL)); 232 rem.tv_sec = 1; 233 ts.tv_sec = 0; 234 ts.tv_nsec = 20 * 1000000; 235 chk_error(nanosleep(&ts, &rem)); 236 if (rem.tv_sec != 1) 237 error("nanosleep"); 238 chk_error(gettimeofday(&tv2, NULL)); 239 ti = tv2.tv_sec - tv.tv_sec; 240 if (ti >= 2) 241 error("gettimeofday"); 242 243 chk_error(getrusage(RUSAGE_SELF, &rusg1)); 244 for(i = 0;i < 10000; i++); 245 chk_error(getrusage(RUSAGE_SELF, &rusg2)); 246 if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 || 247 (rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0) 248 error("getrusage"); 249} 250 251static int server_socket(void) 252{ 253 int val, fd; 254 struct sockaddr_in sockaddr = {}; 255 256 /* server socket */ 257 fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); 258 259 val = 1; 260 chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))); 261 262 sockaddr.sin_family = AF_INET; 263 sockaddr.sin_port = htons(0); /* choose random ephemeral port) */ 264 sockaddr.sin_addr.s_addr = 0; 265 chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); 266 chk_error(listen(fd, 0)); 267 return fd; 268 269} 270 271static int client_socket(uint16_t port) 272{ 273 int fd; 274 struct sockaddr_in sockaddr = {}; 275 276 /* server socket */ 277 fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); 278 sockaddr.sin_family = AF_INET; 279 sockaddr.sin_port = htons(port); 280 inet_aton("127.0.0.1", &sockaddr.sin_addr); 281 chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); 282 return fd; 283} 284 285static const char socket_msg[] = "hello socket\n"; 286 287static void test_socket(void) 288{ 289 int server_fd, client_fd, fd, pid, ret, val; 290 struct sockaddr_in sockaddr; 291 struct sockaddr_in server_addr; 292 socklen_t len, socklen; 293 uint16_t server_port; 294 char buf[512]; 295 296 server_fd = server_socket(); 297 /* find out what port we got */ 298 socklen = sizeof(server_addr); 299 ret = getsockname(server_fd, (struct sockaddr *)&server_addr, &socklen); 300 chk_error(ret); 301 server_port = ntohs(server_addr.sin_port); 302 303 /* test a few socket options */ 304 len = sizeof(val); 305 chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); 306 if (val != SOCK_STREAM) 307 error("getsockopt"); 308 309 pid = chk_error(fork()); 310 if (pid == 0) { 311 client_fd = client_socket(server_port); 312 send(client_fd, socket_msg, sizeof(socket_msg), 0); 313 close(client_fd); 314 exit(0); 315 } 316 len = sizeof(sockaddr); 317 fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len)); 318 319 ret = chk_error(recv(fd, buf, sizeof(buf), 0)); 320 if (ret != sizeof(socket_msg)) 321 error("recv"); 322 if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0) 323 error("socket_msg"); 324 chk_error(close(fd)); 325 chk_error(close(server_fd)); 326} 327 328#define WCOUNT_MAX 512 329 330static void test_pipe(void) 331{ 332 fd_set rfds, wfds; 333 int fds[2], fd_max, ret; 334 uint8_t ch; 335 int wcount, rcount; 336 337 chk_error(pipe(fds)); 338 chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK)); 339 chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK)); 340 wcount = 0; 341 rcount = 0; 342 for(;;) { 343 FD_ZERO(&rfds); 344 fd_max = fds[0]; 345 FD_SET(fds[0], &rfds); 346 347 FD_ZERO(&wfds); 348 FD_SET(fds[1], &wfds); 349 if (fds[1] > fd_max) 350 fd_max = fds[1]; 351 352 ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL)); 353 if (ret > 0) { 354 if (FD_ISSET(fds[0], &rfds)) { 355 chk_error(read(fds[0], &ch, 1)); 356 rcount++; 357 if (rcount >= WCOUNT_MAX) 358 break; 359 } 360 if (FD_ISSET(fds[1], &wfds)) { 361 ch = 'a'; 362 chk_error(write(fds[1], &ch, 1)); 363 wcount++; 364 } 365 } 366 } 367 chk_error(close(fds[0])); 368 chk_error(close(fds[1])); 369} 370 371static int thread1_res; 372static int thread2_res; 373 374static int thread1_func(void *arg) 375{ 376 int i; 377 for(i=0;i<5;i++) { 378 thread1_res++; 379 usleep(10 * 1000); 380 } 381 return 0; 382} 383 384static int thread2_func(void *arg) 385{ 386 int i; 387 for(i=0;i<6;i++) { 388 thread2_res++; 389 usleep(10 * 1000); 390 } 391 return 0; 392} 393 394static void wait_for_child(pid_t pid) 395{ 396 int status; 397 chk_error(waitpid(pid, &status, 0)); 398} 399 400/* For test_clone we must match the clone flags used by glibc, see 401 * CLONE_THREAD_FLAGS in the QEMU source code. 402 */ 403static void test_clone(void) 404{ 405 uint8_t *stack1, *stack2; 406 pid_t pid1, pid2; 407 408 stack1 = malloc(STACK_SIZE); 409 pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, 410 CLONE_VM | CLONE_FS | CLONE_FILES | 411 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, 412 "hello1")); 413 414 stack2 = malloc(STACK_SIZE); 415 pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, 416 CLONE_VM | CLONE_FS | CLONE_FILES | 417 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, 418 "hello2")); 419 420 wait_for_child(pid1); 421 free(stack1); 422 wait_for_child(pid2); 423 free(stack2); 424 425 if (thread1_res != 5 || 426 thread2_res != 6) 427 error("clone"); 428} 429 430/***********************************/ 431 432volatile int alarm_count; 433jmp_buf jmp_env; 434 435static void sig_alarm(int sig) 436{ 437 if (sig != SIGALRM) 438 error("signal"); 439 alarm_count++; 440} 441 442static void sig_segv(int sig, siginfo_t *info, void *puc) 443{ 444 if (sig != SIGSEGV) 445 error("signal"); 446 longjmp(jmp_env, 1); 447} 448 449static void test_signal(void) 450{ 451 struct sigaction act; 452 struct itimerval it, oit; 453 454 /* timer test */ 455 456 alarm_count = 0; 457 458 act.sa_handler = sig_alarm; 459 sigemptyset(&act.sa_mask); 460 act.sa_flags = 0; 461 chk_error(sigaction(SIGALRM, &act, NULL)); 462 463 it.it_interval.tv_sec = 0; 464 it.it_interval.tv_usec = 10 * 1000; 465 it.it_value.tv_sec = 0; 466 it.it_value.tv_usec = 10 * 1000; 467 chk_error(setitimer(ITIMER_REAL, &it, NULL)); 468 chk_error(getitimer(ITIMER_REAL, &oit)); 469 470 while (alarm_count < 5) { 471 usleep(10 * 1000); 472 getitimer(ITIMER_REAL, &oit); 473 } 474 475 it.it_interval.tv_sec = 0; 476 it.it_interval.tv_usec = 0; 477 it.it_value.tv_sec = 0; 478 it.it_value.tv_usec = 0; 479 memset(&oit, 0xff, sizeof(oit)); 480 chk_error(setitimer(ITIMER_REAL, &it, &oit)); 481 482 /* SIGSEGV test */ 483 act.sa_sigaction = sig_segv; 484 sigemptyset(&act.sa_mask); 485 act.sa_flags = SA_SIGINFO; 486 chk_error(sigaction(SIGSEGV, &act, NULL)); 487 if (setjmp(jmp_env) == 0) { 488 /* 489 * clang requires volatile or it will turn this into a 490 * call to abort() instead of forcing a SIGSEGV. 491 */ 492 *(volatile uint8_t *)0 = 0; 493 } 494 495 act.sa_handler = SIG_DFL; 496 sigemptyset(&act.sa_mask); 497 act.sa_flags = 0; 498 chk_error(sigaction(SIGSEGV, &act, NULL)); 499 500 if (sigaction(SIGKILL, &act, NULL) == 0) { 501 error("sigaction(SIGKILL, &act, NULL) must not succeed"); 502 } 503 if (sigaction(SIGSTOP, &act, NULL) == 0) { 504 error("sigaction(SIGSTOP, &act, NULL) must not succeed"); 505 } 506 chk_error(sigaction(SIGKILL, NULL, &act)); 507 chk_error(sigaction(SIGSTOP, NULL, &act)); 508} 509 510#define SHM_SIZE 32768 511 512static void test_shm(void) 513{ 514 void *ptr; 515 int shmid; 516 517 shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); 518 ptr = shmat(shmid, NULL, 0); 519 if (ptr == (void *)-1) { 520 error("shmat"); 521 } 522 523 memset(ptr, 0, SHM_SIZE); 524 525 chk_error(shmctl(shmid, IPC_RMID, 0)); 526 chk_error(shmdt(ptr)); 527} 528 529int main(int argc, char **argv) 530{ 531 test_file(); 532 test_pipe(); 533 test_fork(); 534 test_time(); 535 test_socket(); 536 537 if (argc > 1) { 538 printf("test_clone still considered buggy\n"); 539 test_clone(); 540 } 541 542 test_signal(); 543 test_shm(); 544 return 0; 545}