From 7069a97a14155349545c73084f9f9f6b6380e0f7 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 30 Oct 2014 16:52:15 -0600 Subject: selftests/net: move test out of Makefile into a shell script Currently bpf test run from the Makefile. Move it out of the Makefile to be run from a shell script to allow the test to be run as stand-alone test, in addition to allowing the test run from a make target. Signed-off-by: Shuah Khan Acked-by: David S. Miller --- tools/testing/selftests/net/Makefile | 8 +------- tools/testing/selftests/net/test_bpf.sh | 10 ++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100755 tools/testing/selftests/net/test_bpf.sh (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index c7493b8f9b0e..62f22cc9941c 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -14,12 +14,6 @@ all: $(NET_PROGS) run_tests: all @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]" @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]" - @if /sbin/modprobe test_bpf ; then \ - /sbin/rmmod test_bpf; \ - echo "test_bpf: ok"; \ - else \ - echo "test_bpf: [FAIL]"; \ - exit 1; \ - fi + ./test_bpf.sh clean: $(RM) $(NET_PROGS) diff --git a/tools/testing/selftests/net/test_bpf.sh b/tools/testing/selftests/net/test_bpf.sh new file mode 100755 index 000000000000..8b29796d46aa --- /dev/null +++ b/tools/testing/selftests/net/test_bpf.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Runs bpf test using test_bpf kernel module + +if /sbin/modprobe -q test_bpf ; then + /sbin/modprobe -q -r test_bpf; + echo "test_bpf: ok"; +else + echo "test_bpf: [FAIL]"; + exit 1; +fi -- cgit v1.2.3-59-g8ed1b From 3c25fa14f0bfa21a0b8d5efc3174d0506682658d Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 30 Oct 2014 16:43:48 -0600 Subject: selftests/user: move test out of Makefile into a shell script Currently user copy test is run from the Makefile. Move it out of the Makefile to be run from a shell script to allow the test to be run as stand-alone test, in addition to allowing the test run from a make target. Signed-off-by: Shuah Khan --- tools/testing/selftests/user/Makefile | 8 +------- tools/testing/selftests/user/test_user_copy.sh | 10 ++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100755 tools/testing/selftests/user/test_user_copy.sh (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/user/Makefile b/tools/testing/selftests/user/Makefile index 396255bd720e..12c9d15bab07 100644 --- a/tools/testing/selftests/user/Makefile +++ b/tools/testing/selftests/user/Makefile @@ -4,10 +4,4 @@ all: run_tests: all - @if /sbin/modprobe test_user_copy ; then \ - rmmod test_user_copy; \ - echo "user_copy: ok"; \ - else \ - echo "user_copy: [FAIL]"; \ - exit 1; \ - fi + ./test_user_copy.sh diff --git a/tools/testing/selftests/user/test_user_copy.sh b/tools/testing/selftests/user/test_user_copy.sh new file mode 100755 index 000000000000..350107f40c1d --- /dev/null +++ b/tools/testing/selftests/user/test_user_copy.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Runs copy_to/from_user infrastructure using test_user_copy kernel module + +if /sbin/modprobe -q test_user_copy; then + /sbin/modprobe -q -r test_user_copy + echo "user_copy: ok" +else + echo "user_copy: [FAIL]" + exit 1 +fi -- cgit v1.2.3-59-g8ed1b From 7fb2c3ea28bf7b748923a7cd58b6f49bce491bb7 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 3 Oct 2014 09:04:23 -0600 Subject: selftests: add kselftest framework for uniform test reporting Add kselftest framework for tests to use. This is a light weight framework provides a set of interfaces to report test results. Tests can use these interfaces to report pass, and fail cases as well as when failure is due to configuration problems such as missing modules, or when a test that is should fail, fails as expected, and a test that should fail, passes. The framework uses POSIX standard return codes for reporting results to address the needs of users that want to run the kernel selftests from their user-space test suites and want to know why a test failed. In addition, the framework includes interfaces to use to report test statistics on number of tests passed and failed. Signed-off-by: Shuah Khan --- tools/testing/selftests/kselftest.h | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tools/testing/selftests/kselftest.h (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h new file mode 100644 index 000000000000..572c8888167a --- /dev/null +++ b/tools/testing/selftests/kselftest.h @@ -0,0 +1,62 @@ +/* + * kselftest.h: kselftest framework return codes to include from + * selftests. + * + * Copyright (c) 2014 Shuah Khan + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * This file is released under the GPLv2. + */ +#ifndef __KSELFTEST_H +#define __KSELFTEST_H + +#include +#include + +/* counters */ +struct ksft_count { + unsigned int ksft_pass; + unsigned int ksft_fail; + unsigned int ksft_xfail; + unsigned int ksft_xpass; + unsigned int ksft_xskip; +}; + +static struct ksft_count ksft_cnt; + +static inline void ksft_inc_pass_cnt(void) { ksft_cnt.ksft_pass++; } +static inline void ksft_inc_fail_cnt(void) { ksft_cnt.ksft_fail++; } +static inline void ksft_inc_xfail_cnt(void) { ksft_cnt.ksft_xfail++; } +static inline void ksft_inc_xpass_cnt(void) { ksft_cnt.ksft_xpass++; } +static inline void ksft_inc_xskip_cnt(void) { ksft_cnt.ksft_xskip++; } + +static inline void ksft_print_cnts(void) +{ + printf("Pass: %d Fail: %d Xfail: %d Xpass: %d, Xskip: %d\n", + ksft_cnt.ksft_pass, ksft_cnt.ksft_fail, + ksft_cnt.ksft_xfail, ksft_cnt.ksft_xpass, + ksft_cnt.ksft_xskip); +} + +static inline int ksft_exit_pass(void) +{ + exit(0); +} +static inline int ksft_exit_fail(void) +{ + exit(1); +} +static inline int ksft_exit_xfail(void) +{ + exit(2); +} +static inline int ksft_exit_xpass(void) +{ + exit(3); +} +static inline int ksft_exit_skip(void) +{ + exit(4); +} + +#endif /* __KSELFTEST_H */ -- cgit v1.2.3-59-g8ed1b From b36169041c07378aa17e8afff643aed89be9acd4 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 3 Oct 2014 09:06:22 -0600 Subject: selftests/breakpoints: change test to use ksft framework Change breakpoints test to use kselftest framework to report test results. Signed-off-by: Shuah Khan --- tools/testing/selftests/breakpoints/breakpoint_test.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c index a0743f3b2b57..120895ab5505 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test.c @@ -17,6 +17,8 @@ #include #include +#include "../kselftest.h" + /* Breakpoint access modes */ enum { @@ -42,7 +44,7 @@ static void set_breakpoint_addr(void *addr, int n) offsetof(struct user, u_debugreg[n]), addr); if (ret) { perror("Can't set breakpoint addr\n"); - exit(-1); + ksft_exit_fail(); } } @@ -105,7 +107,7 @@ static void toggle_breakpoint(int n, int type, int len, offsetof(struct user, u_debugreg[7]), dr7); if (ret) { perror("Can't set dr7"); - exit(-1); + ksft_exit_fail(); } } @@ -275,7 +277,7 @@ static void check_success(const char *msg) msg2 = "Ok"; if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) { perror("Can't poke\n"); - exit(-1); + ksft_exit_fail(); } } @@ -390,5 +392,5 @@ int main(int argc, char **argv) wait(NULL); - return 0; + return ksft_exit_pass(); } -- cgit v1.2.3-59-g8ed1b From 56661564e1fea94c42289edd59361a1f87932410 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 3 Oct 2014 09:07:12 -0600 Subject: selftests/ipc: change test to use ksft framework Change ipc test to use kselftest framework to report test results. With this change this test exits with EXIT_FAIL instead of -errno. Changed print errno in test fail messages to not loose that information. Signed-off-by: Shuah Khan --- tools/testing/selftests/ipc/msgque.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index 552f0810bffb..1b2ce334bb3f 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c @@ -5,6 +5,8 @@ #include #include +#include "../kselftest.h" + #define MAX_MSG_SIZE 32 struct msg1 { @@ -195,58 +197,58 @@ int main(int argc, char **argv) if (getuid() != 0) { printf("Please run the test as root - Exiting.\n"); - exit(1); + return ksft_exit_fail(); } msgque.key = ftok(argv[0], 822155650); if (msgque.key == -1) { - printf("Can't make key\n"); - return -errno; + printf("Can't make key: %d\n", -errno); + return ksft_exit_fail(); } msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); if (msgque.msq_id == -1) { err = -errno; - printf("Can't create queue\n"); + printf("Can't create queue: %d\n", err); goto err_out; } err = fill_msgque(&msgque); if (err) { - printf("Failed to fill queue\n"); + printf("Failed to fill queue: %d\n", err); goto err_destroy; } err = dump_queue(&msgque); if (err) { - printf("Failed to dump queue\n"); + printf("Failed to dump queue: %d\n", err); goto err_destroy; } err = check_and_destroy_queue(&msgque); if (err) { - printf("Failed to check and destroy queue\n"); + printf("Failed to check and destroy queue: %d\n", err); goto err_out; } err = restore_queue(&msgque); if (err) { - printf("Failed to restore queue\n"); + printf("Failed to restore queue: %d\n", err); goto err_destroy; } err = check_and_destroy_queue(&msgque); if (err) { - printf("Failed to test queue\n"); + printf("Failed to test queue: %d\n", err); goto err_out; } - return 0; + return ksft_exit_pass(); err_destroy: if (msgctl(msgque.msq_id, IPC_RMID, 0)) { printf("Failed to destroy queue: %d\n", -errno); - return -errno; + return ksft_exit_fail(); } err_out: - return err; + return ksft_exit_fail(); } -- cgit v1.2.3-59-g8ed1b From e061bcd88573863daef2c67888ced5333b2ba536 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 3 Oct 2014 09:08:14 -0600 Subject: selftests/kcmp: change test to use ksft framework Change kcmp test to use kselftest framework to report test results and test statistics. Signed-off-by: Shuah Khan --- tools/testing/selftests/kcmp/kcmp_test.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c index dbba4084869c..a5a4da856dfe 100644 --- a/tools/testing/selftests/kcmp/kcmp_test.c +++ b/tools/testing/selftests/kcmp/kcmp_test.c @@ -17,6 +17,8 @@ #include #include +#include "../kselftest.h" + static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2) { return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); @@ -34,13 +36,13 @@ int main(int argc, char **argv) if (fd1 < 0) { perror("Can't create file"); - exit(1); + ksft_exit_fail(); } pid2 = fork(); if (pid2 < 0) { perror("fork failed"); - exit(1); + ksft_exit_fail(); } if (!pid2) { @@ -50,7 +52,7 @@ int main(int argc, char **argv) fd2 = open(kpath, O_RDWR, 0644); if (fd2 < 0) { perror("Can't open file"); - exit(1); + ksft_exit_fail(); } /* An example of output and arguments */ @@ -74,23 +76,34 @@ int main(int argc, char **argv) if (ret) { printf("FAIL: 0 expected but %d returned (%s)\n", ret, strerror(errno)); + ksft_inc_fail_cnt(); ret = -1; - } else + } else { printf("PASS: 0 returned as expected\n"); + ksft_inc_pass_cnt(); + } /* Compare with self */ ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0); if (ret) { printf("FAIL: 0 expected but %d returned (%s)\n", ret, strerror(errno)); + ksft_inc_fail_cnt(); ret = -1; - } else + } else { printf("PASS: 0 returned as expected\n"); + ksft_inc_pass_cnt(); + } + + ksft_print_cnts(); - exit(ret); + if (ret) + ksft_exit_fail(); + else + ksft_exit_pass(); } waitpid(pid2, &status, P_ALL); - return 0; + return ksft_exit_pass(); } -- cgit v1.2.3-59-g8ed1b From 884716497d4c777f4b8798fab361b4bad351f5bc Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 3 Oct 2014 09:08:56 -0600 Subject: selftests/timers: change test to use ksft framework Change timers test to use kselftest framework to report test results. Signed-off-by: Shuah Khan --- tools/testing/selftests/timers/posix_timers.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c index 41bd85559d4b..f87d970a485c 100644 --- a/tools/testing/selftests/timers/posix_timers.c +++ b/tools/testing/selftests/timers/posix_timers.c @@ -15,6 +15,8 @@ #include #include +#include "../kselftest.h" + #define DELAY 2 #define USECS_PER_SEC 1000000 @@ -194,16 +196,16 @@ int main(int argc, char **argv) printf("based timers if other threads run on the CPU...\n"); if (check_itimer(ITIMER_VIRTUAL) < 0) - return -1; + return ksft_exit_fail(); if (check_itimer(ITIMER_PROF) < 0) - return -1; + return ksft_exit_fail(); if (check_itimer(ITIMER_REAL) < 0) - return -1; + return ksft_exit_fail(); if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) - return -1; + return ksft_exit_fail(); /* * It's unfortunately hard to reliably test a timer expiration @@ -215,7 +217,7 @@ int main(int argc, char **argv) * find a better solution. */ if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) - return -1; + return ksft_exit_fail(); - return 0; + return ksft_exit_pass(); } -- cgit v1.2.3-59-g8ed1b From 41ec8cdcfaf98db194807ac38a685b52387604c3 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 2 Dec 2014 16:52:07 +1100 Subject: selftests/kcmp: Don't include kernel headers The kcmp test mucks with the include path to bring in the kernel headers, and x86 headers too for reasons that are not clear. Now that kcmp.h is exported none of that should be necessary. Signed-off-by: Michael Ellerman Acked-by: Cyrill Gorcunov Signed-off-by: Shuah Khan --- tools/testing/selftests/kcmp/Makefile | 4 ---- 1 file changed, 4 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile index 8aabd82db9e4..4f00c0524501 100644 --- a/tools/testing/selftests/kcmp/Makefile +++ b/tools/testing/selftests/kcmp/Makefile @@ -8,11 +8,7 @@ ifeq ($(ARCH),x86_64) ARCH := x86 CFLAGS := -DCONFIG_X86_64 -D__x86_64__ endif - -CFLAGS += -I../../../../arch/x86/include/generated/ -CFLAGS += -I../../../../include/ CFLAGS += -I../../../../usr/include/ -CFLAGS += -I../../../../arch/x86/include/ all: ifeq ($(ARCH),x86) -- cgit v1.2.3-59-g8ed1b From 4c12df63f7ff27fe2e14f243a6906ad84e641964 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 2 Dec 2014 16:52:08 +1100 Subject: selftests/kcmp: Always try to build the test Don't prevent the test building on non-x86. Just try and build it and let the chips fall where they may. Add support for CROSS_COMPILE while we're at it. Also we don't need a custom rule for building kcmp_test. Signed-off-by: Michael Ellerman Reviewed-by: Christopher Covington Signed-off-by: Shuah Khan --- tools/testing/selftests/kcmp/Makefile | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile index 4f00c0524501..ff0eefdc6ceb 100644 --- a/tools/testing/selftests/kcmp/Makefile +++ b/tools/testing/selftests/kcmp/Makefile @@ -1,21 +1,7 @@ -uname_M := $(shell uname -m 2>/dev/null || echo not) -ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) -ifeq ($(ARCH),i386) - ARCH := x86 - CFLAGS := -DCONFIG_X86_32 -D__i386__ -endif -ifeq ($(ARCH),x86_64) - ARCH := x86 - CFLAGS := -DCONFIG_X86_64 -D__x86_64__ -endif +CC := $(CROSS_COMPILE)$(CC) CFLAGS += -I../../../../usr/include/ -all: -ifeq ($(ARCH),x86) - gcc $(CFLAGS) kcmp_test.c -o kcmp_test -else - echo "Not an x86 target, can't build kcmp selftest" -endif +all: kcmp_test run_tests: all @./kcmp_test || echo "kcmp_test: [FAIL]" -- cgit v1.2.3-59-g8ed1b From 3ce51050fadd63737c03627293ca2dc4be238891 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Wed, 3 Dec 2014 10:42:21 -0800 Subject: selftest: size: Add size test for Linux kernel This test shows the amount of memory used by the system. Note that this is dependent on the user-space that is loaded when this program runs. Optimally, this program would be run as the init program itself. The program is optimized for size itself, to avoid conflating its own execution with that of the system software. The code is compiled statically, with no stdlibs. On my x86_64 system, this results in a statically linked binary of less than 5K. Signed-off-by: Tim Bird Reviewed-by: Josh Triplett Signed-off-by: Shuah Khan --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/size/.gitignore | 1 + tools/testing/selftests/size/Makefile | 12 ++++ tools/testing/selftests/size/get_size.c | 100 ++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 tools/testing/selftests/size/.gitignore create mode 100644 tools/testing/selftests/size/Makefile create mode 100644 tools/testing/selftests/size/get_size.c (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 45f145c6f843..fa91aefc8d19 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -15,6 +15,7 @@ TARGETS += user TARGETS += sysctl TARGETS += firmware TARGETS += ftrace +TARGETS += size TARGETS_HOTPLUG = cpu-hotplug TARGETS_HOTPLUG += memory-hotplug diff --git a/tools/testing/selftests/size/.gitignore b/tools/testing/selftests/size/.gitignore new file mode 100644 index 000000000000..189b7818de34 --- /dev/null +++ b/tools/testing/selftests/size/.gitignore @@ -0,0 +1 @@ +get_size diff --git a/tools/testing/selftests/size/Makefile b/tools/testing/selftests/size/Makefile new file mode 100644 index 000000000000..04dc25e4fa92 --- /dev/null +++ b/tools/testing/selftests/size/Makefile @@ -0,0 +1,12 @@ +CC = $(CROSS_COMPILE)gcc + +all: get_size + +get_size: get_size.c + $(CC) -static -ffreestanding -nostartfiles -s $< -o $@ + +run_tests: all + ./get_size + +clean: + $(RM) get_size diff --git a/tools/testing/selftests/size/get_size.c b/tools/testing/selftests/size/get_size.c new file mode 100644 index 000000000000..2d1af7cca463 --- /dev/null +++ b/tools/testing/selftests/size/get_size.c @@ -0,0 +1,100 @@ +/* + * Copyright 2014 Sony Mobile Communications Inc. + * + * Licensed under the terms of the GNU GPL License version 2 + * + * Selftest for runtime system size + * + * Prints the amount of RAM that the currently running system is using. + * + * This program tries to be as small as possible itself, to + * avoid perturbing the system memory utilization with its + * own execution. It also attempts to have as few dependencies + * on kernel features as possible. + * + * It should be statically linked, with startup libs avoided. + * It uses no library calls, and only the following 3 syscalls: + * sysinfo(), write(), and _exit() + * + * For output, it avoids printf (which in some C libraries + * has large external dependencies) by implementing it's own + * number output and print routines, and using __builtin_strlen() + */ + +#include +#include + +#define STDOUT_FILENO 1 + +static int print(const char *s) +{ + return write(STDOUT_FILENO, s, __builtin_strlen(s)); +} + +static inline char *num_to_str(unsigned long num, char *buf, int len) +{ + unsigned int digit; + + /* put digits in buffer from back to front */ + buf += len - 1; + *buf = 0; + do { + digit = num % 10; + *(--buf) = digit + '0'; + num /= 10; + } while (num > 0); + + return buf; +} + +static int print_num(unsigned long num) +{ + char num_buf[30]; + + return print(num_to_str(num, num_buf, sizeof(num_buf))); +} + +static int print_k_value(const char *s, unsigned long num, unsigned long units) +{ + unsigned long long temp; + int ccode; + + print(s); + + temp = num; + temp = (temp * units)/1024; + num = temp; + ccode = print_num(num); + print("\n"); + return ccode; +} + +/* this program has no main(), as startup libraries are not used */ +void _start(void) +{ + int ccode; + struct sysinfo info; + unsigned long used; + + print("Testing system size.\n"); + print("1..1\n"); + + ccode = sysinfo(&info); + if (ccode < 0) { + print("not ok 1 get runtime memory use\n"); + print("# could not get sysinfo\n"); + _exit(ccode); + } + /* ignore cache complexities for now */ + used = info.totalram - info.freeram - info.bufferram; + print_k_value("ok 1 get runtime memory use # size = ", used, + info.mem_unit); + + print("# System runtime memory report (units in Kilobytes):\n"); + print_k_value("# Total: ", info.totalram, info.mem_unit); + print_k_value("# Free: ", info.freeram, info.mem_unit); + print_k_value("# Buffer: ", info.bufferram, info.mem_unit); + print_k_value("# In use: ", used, info.mem_unit); + + _exit(0); +} -- cgit v1.2.3-59-g8ed1b