add: testcases for refs #885, refs #1031

This commit is contained in:
Ken Sato
2018-03-01 10:24:21 +09:00
parent 140f813d77
commit afcf1a24aa
27 changed files with 1677 additions and 5 deletions

View File

@ -0,0 +1,63 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_001"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int pid = 0;
int status;
int tmp_flag = 0;
struct sigaction sa;
printf("*** %s start *******************************\n", TEST_NAME);
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
sa.sa_handler = test_handler;
sa.sa_flags = SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
printf(" send 2nd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(1, "can't reach here");
} else { /* parent */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (WIFSIGNALED(status)) {
if (WTERMSIG(status) == SIGUSR1) {
tmp_flag = 1;
}
}
OKNG(tmp_flag != 1, "child is killed by SIGUSR1");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_002"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int pid = 0;
int status;
int tmp_flag = 0;
struct sigaction sa;
printf("*** %s start *******************************\n", TEST_NAME);
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
sa.sa_handler = test_handler;
sa.sa_flags = 0;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction (no SA_RESETHAND)");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
printf(" send 2nd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 2, "invoked test_handler again");
_exit(123);
} else { /* parent */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (!WIFSIGNALED(status) &&
WIFEXITED(status)) {
if (WEXITSTATUS(status) == 123) {
tmp_flag = 1;
}
}
OKNG(tmp_flag != 1, "child exited normaly");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_003"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int pid = 0;
int status;
int tmp_flag = 0;
struct sigaction sa;
printf("*** %s start *******************************\n", TEST_NAME);
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
sa.sa_handler = test_handler;
sa.sa_flags |= SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND");
sa.sa_flags = 0;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction (rewrite no SA_RESETHAND)");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
printf(" send 2nd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 2, "invoked test_handler again");
_exit(123);
} else { /* parent */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (!WIFSIGNALED(status) &&
WIFEXITED(status)) {
if (WEXITSTATUS(status) == 123) {
tmp_flag = 1;
}
}
OKNG(tmp_flag != 1, "child exited normaly");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,81 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_004"
int handled_cnt = 0;
int handled_cnt2 = 0;
void test_handler(int sig)
{
handled_cnt++;
}
void test_handler2(int sig)
{
handled_cnt2++;
}
int main(int argc, char** argv)
{
int rc = 0;
int pid = 0;
int status;
int tmp_flag = 0;
struct sigaction sa;
struct sigaction sa2;
printf("*** %s start *******************************\n", TEST_NAME);
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
sa.sa_handler = test_handler;
sa.sa_flags |= SA_RESETHAND;
sa2.sa_handler = test_handler2;
sa2.sa_flags |= SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND to SIGUSR1");
rc = sigaction(SIGUSR2, &sa2, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND to SIGUSR2");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
printf(" send 1st SIGUSR2\n");
kill(getpid(), SIGUSR2);
OKNG(handled_cnt2 != 1, "invoked test_handler2");
printf(" send 2nd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(1, "can't reach here");
} else { /* parent */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (WIFSIGNALED(status)) {
if (WTERMSIG(status) == SIGUSR1) {
tmp_flag = 1;
}
}
OKNG(tmp_flag != 1, "child is killed by SIGUSR1");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_005"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int pid = 0;
int status;
int tmp_flag = 0;
struct sigaction sa;
printf("*** %s start *******************************\n", TEST_NAME);
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
sa.sa_handler = test_handler;
sa.sa_flags = SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND again");
printf(" send 2nd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 2, "invoked test_handler again");
printf(" send 3rd SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(1, "can't reach here");
} else { /* parent */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (WIFSIGNALED(status)) {
if (WTERMSIG(status) == SIGUSR1) {
tmp_flag = 1;
}
}
OKNG(tmp_flag != 1, "child is killed by SIGUSR1");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,49 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_006"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int status;
int tmp_flag = 0;
struct sigaction sa, old_act;
printf("*** %s start *******************************\n", TEST_NAME);
sa.sa_handler = test_handler;
sa.sa_flags = SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND");
rc = sigaction(SIGUSR1, NULL, &old_act);
OKNG(rc != 0, "sigaction to get current action");
if (old_act.sa_handler == test_handler &&
old_act.sa_flags & SA_RESETHAND) {
tmp_flag = 1;
}
OKNG(tmp_flag != 1, "check current act");
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,52 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_007"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int status;
int tmp_flag = 0;
struct sigaction sa, old_act;
printf("*** %s start *******************************\n", TEST_NAME);
sa.sa_handler = test_handler;
sa.sa_flags = SA_RESETHAND;
rc = sigaction(SIGUSR1, &sa, NULL);
OKNG(rc != 0, "sigaction with SA_RESETHAND");
printf(" send 1st SIGUSR1\n");
kill(getpid(), SIGUSR1);
OKNG(handled_cnt != 1, "invoked test_handler");
rc = sigaction(SIGUSR1, NULL, &old_act);
OKNG(rc != 0, "sigaction to get current action");
if (old_act.sa_handler == SIG_DFL) {
tmp_flag = 1;
}
OKNG(tmp_flag != 1, "check current act (after reset)");
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_008"
int handled_cnt = 0;
void test_handler(int sig)
{
handled_cnt++;
}
int main(int argc, char** argv)
{
int rc = 0;
int status;
int tmp_flag = 0;
struct sigaction sa, old_act;
printf("*** %s start *******************************\n", TEST_NAME);
rc = sigaction(0, &sa, NULL);
OKNG(rc != -1, "sigaction 0 failed");
rc = sigaction(_NSIG, &sa, NULL);
OKNG(rc != -1, "sigaction _NSIG failed");
rc = sigaction(SIGKILL, &sa, NULL);
OKNG(rc != -1, "sigaction SIGKILL failed");
rc = sigaction(SIGSTOP, &sa, NULL);
OKNG(rc != -1, "sigaction SIGSTOP failed");
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_009"
int main(int argc, char** argv)
{
int rc = 0;
int status;
int tmp_flag = 0;
struct sigaction old_act;
printf("*** %s start *******************************\n", TEST_NAME);
rc = sigaction(SIGKILL, NULL, &old_act);
OKNG(rc != 0, "sigaction to get SIGKILL action");
if (old_act.sa_handler == SIG_DFL) {
tmp_flag = 1;
}
OKNG(tmp_flag != 1, "check SIGKILL act");
rc = sigaction(SIGKILL, NULL, &old_act);
OKNG(rc != 0, "sigaction to get SIGSTOP action");
tmp_flag = 0;
if (old_act.sa_handler == SIG_DFL) {
tmp_flag = 1;
}
OKNG(tmp_flag != 1, "check SIGSTOP act");
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "./test_chk.h"
#define TEST_NAME "CT_010"
int main(int argc, char** argv)
{
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
rc = sigaction(SIGUSR1, NULL, NULL);
OKNG(rc != 0, "SIGUSR1 is valid");
rc = sigaction(SIGKILL, NULL, NULL);
OKNG(rc != 0, "SIGKILL is valid");
rc = sigaction(SIGSTOP, NULL, NULL);
OKNG(rc != 0, "SIGSTOP is valid");
rc = sigaction(_NSIG, NULL, NULL);
OKNG(rc != -1, "_NSIG is invalid");
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,56 @@
CC = gcc
MCK_DIR=/home/satoken/ppos
MCEXEC=$(MCK_DIR)/bin/mcexec
TARGET=CT_001 CT_002 CT_003 CT_004 CT_005 CT_006 CT_007 CT_008 CT_009 CT_010
CPPFLAGS =
LDFLAGS =
all: $(TARGET)
CT_001: CT_001.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_002: CT_002.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_003: CT_003.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_004: CT_004.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_005: CT_005.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_006: CT_006.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_007: CT_007.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_008: CT_008.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_009: CT_009.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_010: CT_010.c
$(CC) -o $@ $^ $(LDFLAGS)
test: all
$(MCEXEC) ./CT_001
$(MCEXEC) ./CT_002
$(MCEXEC) ./CT_003
$(MCEXEC) ./CT_004
$(MCEXEC) ./CT_005
$(MCEXEC) ./CT_006
$(MCEXEC) ./CT_007
$(MCEXEC) ./CT_008
$(MCEXEC) ./CT_009
$(MCEXEC) ./CT_010
clean:
rm -f $(TARGET) *.o

View File

@ -85,6 +85,7 @@ CT_010: sig_numの有効確認
1. sigaction(SIGUSR1, NULL, NULL) で有効かどうかを確認 1. sigaction(SIGUSR1, NULL, NULL) で有効かどうかを確認
2. sigaction(SIGKILL, NULL, NULL) で有効かどうかを確認 2. sigaction(SIGKILL, NULL, NULL) で有効かどうかを確認
3. sigaction(SIGSTOP, NULL, NULL) で有効かどうかを確認 3. sigaction(SIGSTOP, NULL, NULL) で有効かどうかを確認
4. sigaction(_NSIG, NULL, NULL) で有効かどうかを確認
3. 結果 3. 結果
テストプログラムの実行結果をresult.log に示す。 テストプログラムの実行結果をresult.log に示す。

View File

@ -0,0 +1,105 @@
①Issueで報告されたテストプログラムによる確認
$ mcexec ./test_mck -s rt_sigaction -n 4
TEST_SUITE: rt_sigaction
TEST_NUMBER: 4
ARGS:
/-------- Signal handler will activate -------/
sig#10 is handled.
/------ Process will terminate by signal -----/
Terminate by signal 10
User defined signal 1
②McKernelでのsigaction()の基本動作確認
/home/satoken/ppos/bin/mcexec ./CT_001
*** CT_001 start *******************************
[OK] sigaction with SA_RESETHAND
send 1st SIGUSR1
[OK] invoked test_handler
send 2nd SIGUSR1
[OK] child is killed by SIGUSR1
*** CT_001 PASSED
/home/satoken/ppos/bin/mcexec ./CT_002
*** CT_002 start *******************************
[OK] sigaction (no SA_RESETHAND)
send 1st SIGUSR1
[OK] invoked test_handler
send 2nd SIGUSR1
[OK] invoked test_handler again
[OK] child exited normaly
*** CT_002 PASSED
/home/satoken/ppos/bin/mcexec ./CT_003
*** CT_003 start *******************************
[OK] sigaction with SA_RESETHAND
[OK] sigaction (rewrite no SA_RESETHAND)
send 1st SIGUSR1
[OK] invoked test_handler
send 2nd SIGUSR1
[OK] invoked test_handler again
[OK] child exited normaly
*** CT_003 PASSED
/home/satoken/ppos/bin/mcexec ./CT_004
*** CT_004 start *******************************
[OK] sigaction with SA_RESETHAND to SIGUSR1
[OK] sigaction with SA_RESETHAND to SIGUSR2
send 1st SIGUSR1
[OK] invoked test_handler
send 1st SIGUSR2
[OK] invoked test_handler2
send 2nd SIGUSR1
[OK] child is killed by SIGUSR1
*** CT_004 PASSED
/home/satoken/ppos/bin/mcexec ./CT_005
*** CT_005 start *******************************
[OK] sigaction with SA_RESETHAND
send 1st SIGUSR1
[OK] invoked test_handler
[OK] sigaction with SA_RESETHAND again
send 2nd SIGUSR1
[OK] invoked test_handler again
send 3rd SIGUSR1
[OK] child is killed by SIGUSR1
*** CT_005 PASSED
/home/satoken/ppos/bin/mcexec ./CT_006
*** CT_006 start *******************************
[OK] sigaction with SA_RESETHAND
[OK] sigaction to get current action
[OK] check current act
*** CT_006 PASSED
/home/satoken/ppos/bin/mcexec ./CT_007
*** CT_007 start *******************************
[OK] sigaction with SA_RESETHAND
send 1st SIGUSR1
[OK] invoked test_handler
[OK] sigaction to get current action
[OK] check current act (after reset)
*** CT_007 PASSED
/home/satoken/ppos/bin/mcexec ./CT_008
*** CT_008 start *******************************
[OK] sigaction 0 failed
[OK] sigaction _NSIG failed
[OK] sigaction SIGKILL failed
[OK] sigaction SIGSTOP failed
*** CT_008 PASSED
/home/satoken/ppos/bin/mcexec ./CT_009
*** CT_009 start *******************************
[OK] sigaction to get SIGKILL action
[OK] check SIGKILL act
[OK] sigaction to get SIGSTOP action
[OK] check SIGSTOP act
*** CT_009 PASSED
/home/satoken/ppos/bin/mcexec ./CT_010
*** CT_010 start *******************************
[OK] SIGUSR1 is valid
[OK] SIGKILL is valid
[OK] SIGSTOP is valid
[OK] _NSIG is invalid
*** CT_010 PASSED

View File

@ -0,0 +1,25 @@
#ifndef HEADER_TEST_CHK_H
#define HEADER_TEST_CHK_H
#define CHKANDJUMP(cond, ...) \
do { \
if (cond) { \
fprintf(stderr, " [NG] "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " failed\n"); \
goto fn_fail; \
} \
} while(0);
#define OKNG(cond, ...) \
do { \
if (cond) { \
CHKANDJUMP(cond, __VA_ARGS__); \
} else { \
fprintf(stdout, " [OK] "); \
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
} \
} while(0);
#endif

View File

@ -0,0 +1,77 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_001"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* detach child */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_detach");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,77 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_002"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* continue child */
rc = ptrace(PTRACE_CONT, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_cont");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,80 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_003"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
sleep(1);
OKNG(getppid() != 1, "orphan process");
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* continue child */
rc = ptrace(PTRACE_CONT, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_cont");
_exit(0);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,123 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_004"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* detach child */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_detach");
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach again");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
if (WIFEXITED(status)) {
printf("exited:%d\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("signaled\n");
}
if (WIFCONTINUED(status)) {
printf("continued\n");
}
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped again");
/* detach child */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_detach again");
/* wake child */
sem_post(cwait);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,76 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_005"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* invalid attach */
rc = ptrace(PTRACE_ATTACH, 0, NULL, NULL);
OKNG(rc == 0, "ptrace_attach 0 failed [invalid pid]");
/* invalid attach */
rc = ptrace(PTRACE_ATTACH, 1, NULL, NULL);
OKNG(rc == 0, "ptrace_attach 1 failed [invalid pid]");
/* invalid attach */
rc = ptrace(PTRACE_ATTACH, getpid(), NULL, NULL);
OKNG(rc == 0, "ptrace_attach self failed [invalid pid]");
/* wake child */
sem_post(cwait);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,81 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_006"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* normal attach */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* attach twice*/
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc == 0, "ptrace_attach failed [double attach]");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* detach child */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_detach");
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,69 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_007"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
rc = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach after traceme*/
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc == 0, "ptrace_attach failed [after traceme]");
/* wake child */
sem_post(cwait);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,80 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_008"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* invalid detach */
rc = ptrace(PTRACE_DETACH, 0, NULL, NULL);
OKNG(rc == 0, "ptrace_detach 0 failed [invalid pid]");
/* invalid detach */
rc = ptrace(PTRACE_DETACH, 1, NULL, NULL);
OKNG(rc == 0, "ptrace_detach 1 failed [invalid pid]");
/* invalid detach */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc == 0, "ptrace_detach child failed [not attached]");
/* invalid detach */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc == 0, "ptrace_detach self failed [invalid pid]");
/* wake child */
sem_post(cwait);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,87 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "./test_chk.h"
#define TEST_NAME "CT_009"
int main(int argc, char** argv)
{
pid_t pid = 0;
sem_t *pwait = NULL;
sem_t *cwait = NULL;
void *mem, *attach;
int rc = 0;
int status;
printf("*** %s start *******************************\n", TEST_NAME);
pwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
cwait = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHKANDJUMP(!pwait || !cwait, "mmap for sem");
rc |= sem_init(pwait, 1, 0);
rc |= sem_init(cwait, 1, 0);
CHKANDJUMP(rc, "sem_init");
pid = fork();
CHKANDJUMP(pid == -1, "fork");
if (pid == 0) { /* child */
/* wake parent */
sem_post(pwait);
/* wait */
sem_wait(cwait);
/* wait */
sem_wait(cwait);
_exit(123);
} else { /* parent */
/* wait */
sem_wait(pwait);
/* attach child */
rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_attach");
/* wake child */
sem_post(cwait);
/* wait child stop */
rc = waitpid(pid, &status, 0);
CHKANDJUMP(rc == -1, "waitpid");
CHKANDJUMP(!WIFSTOPPED(status), "child is not stopped");
/* detach child */
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc != 0, "ptrace_detach");
/* detach child twice*/
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
OKNG(rc == 0, "ptrace_detach faild [double detach]");
/* wake child */
sem_post(cwait);
}
printf("*** %s PASSED\n\n", TEST_NAME);
return 0;
fn_fail:
printf("*** %s FAILED\n\n", TEST_NAME);
return -1;
}

View File

@ -0,0 +1,53 @@
CC = gcc
MCK_DIR=/home/satoken/ppos
MCEXEC=$(MCK_DIR)/bin/mcexec
TARGET=CT_001 CT_002 CT_003 CT_004 CT_005 CT_006 CT_007 CT_008 CT_009
CPPFLAGS =
LDFLAGS = -pthread
all: $(TARGET)
CT_001: CT_001.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_002: CT_002.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_003: CT_003.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_004: CT_004.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_005: CT_005.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_006: CT_006.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_007: CT_007.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_008: CT_008.c
$(CC) -o $@ $^ $(LDFLAGS)
CT_009: CT_009.c
$(CC) -o $@ $^ $(LDFLAGS)
test: all
$(MCEXEC) ./CT_001
$(MCEXEC) ./CT_002
$(MCEXEC) ./CT_003
@sleep 2
$(MCEXEC) ./CT_004
$(MCEXEC) ./CT_005
$(MCEXEC) ./CT_006
$(MCEXEC) ./CT_007
$(MCEXEC) ./CT_008
$(MCEXEC) ./CT_009
clean:
rm -f $(TARGET) *.o

View File

@ -1,6 +1,6 @@
【Issue#885 動作確認】 【Issue#885 動作確認】
Issue#885が解決され、既存機能に影響がないことをIssueで報告されたテストプログラム2項目と、 Issue#885が解決され、既存機能に影響がないことをIssueで報告されたテストプログラム2項目と、
McKernelでのptraceのattach/detach操作の基本動作確認8項目の計10項目のテストによって確認した。 McKernelでのptraceのattach/detach操作の基本動作確認9項目の計11項目のテストによって確認した。
なお、各テストの実行結果は./result.log として格納している。 なお、各テストの実行結果は./result.log として格納している。
①Issueで報告されたテストプログラムによる確認 ①Issueで報告されたテストプログラムによる確認
@ -45,15 +45,17 @@ CT_005: 不正なpid指定のattach
1. 不正なpid(0, 1, 負数)を指定したattach 1. 不正なpid(0, 1, 負数)を指定したattach
2. 自身のpidを指定したattach 2. 自身のpidを指定したattach
CT_006: attach済の子プロセスへのattach CT_006: attach済の子プロセスへのattach
1. 既にattachしている子プロセスへ再びattach 1. 既にattachしている子プロセスへ再びattach
2. tracemeした子プロセスへattach
CT_007: 不正なpid指定のdetach CT_007: attach済の子プロセスへのattach
1. tracemeした子プロセスへattach
CT_008: 不正なpid指定のdetach
1. 不正なpid(0, 1, 負数)を指定したdetach 1. 不正なpid(0, 1, 負数)を指定したdetach
2. attachしていない子プロセスのpidを指定したdetach 2. attachしていない子プロセスのpidを指定したdetach
CT_008: detach済の子プロセスへのdetach CT_009: detach済の子プロセスへのdetach
1. 既にdetachしていいる子プロセスへ再びdetach 1. 既にdetachしていいる子プロセスへ再びdetach
3. 結果 3. 結果

View File

@ -0,0 +1,78 @@
①Issueで報告されたテストプログラムによる確認
$ mcexec test_set/bin/test_mck -s ptrace -n 19
TEST_SUITE: ptrace
TEST_NUMBER: 19
ARGS:
child is stopped.
RESULT: ok
$ mcexec test_set/bin/test_mck -s ptrace -n 20
TEST_SUITE: ptrace
TEST_NUMBER: 20
ARGS:
child detach OK.
RESULT: ok
②McKernelでのptraceのattach/detachの基本動作確認
/home/satoken/ppos/bin/mcexec ./CT_001
*** CT_001 start *******************************
[OK] ptrace_attach
[OK] ptrace_detach
*** CT_001 PASSED
/home/satoken/ppos/bin/mcexec ./CT_002
*** CT_002 start *******************************
[OK] ptrace_attach
[OK] ptrace_cont
*** CT_002 PASSED
/home/satoken/ppos/bin/mcexec ./CT_003
*** CT_003 start *******************************
[OK] ptrace_attach
[OK] ptrace_cont
[OK] orphan process
*** CT_003 PASSED
/home/satoken/ppos/bin/mcexec ./CT_004
*** CT_004 start *******************************
[OK] ptrace_attach
[OK] ptrace_detach
[OK] ptrace_attach again
[OK] ptrace_detach again
*** CT_004 PASSED
/home/satoken/ppos/bin/mcexec ./CT_005
*** CT_005 start *******************************
[OK] ptrace_attach 0 failed [invalid pid]
[OK] ptrace_attach 1 failed [invalid pid]
[OK] ptrace_attach self failed [invalid pid]
*** CT_005 PASSED
/home/satoken/ppos/bin/mcexec ./CT_006
*** CT_006 start *******************************
[OK] ptrace_attach
[OK] ptrace_attach failed [double attach]
[OK] ptrace_detach
*** CT_006 PASSED
/home/satoken/ppos/bin/mcexec ./CT_007
*** CT_007 start *******************************
[OK] ptrace_attach failed [after traceme]
*** CT_007 PASSED
/home/satoken/ppos/bin/mcexec ./CT_008
*** CT_008 start *******************************
[OK] ptrace_detach 0 failed [invalid pid]
[OK] ptrace_detach 1 failed [invalid pid]
[OK] ptrace_detach child failed [not attached]
[OK] ptrace_detach self failed [invalid pid]
*** CT_008 PASSED
/home/satoken/ppos/bin/mcexec ./CT_009
*** CT_009 start *******************************
[OK] ptrace_attach
[OK] ptrace_detach
[OK] ptrace_detach faild [double detach]
*** CT_009 PASSED

View File

@ -0,0 +1,25 @@
#ifndef HEADER_TEST_CHK_H
#define HEADER_TEST_CHK_H
#define CHKANDJUMP(cond, ...) \
do { \
if (cond) { \
fprintf(stderr, " [NG] "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " failed\n"); \
goto fn_fail; \
} \
} while(0);
#define OKNG(cond, ...) \
do { \
if (cond) { \
CHKANDJUMP(cond, __VA_ARGS__); \
} else { \
fprintf(stdout, " [OK] "); \
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
} \
} while(0);
#endif