├── .gitignore ├── CHANGELOG.md ├── Config.kmk ├── LICENSE ├── Makefile.kmk ├── README.md └── src ├── Makefile.kmk ├── beginthread.c ├── exeinfo ├── exeinfo.c ├── libcx │ └── exeinfo.h ├── tst-exeinfo-rc.h ├── tst-exeinfo.c └── tst-exeinfo.rc ├── fcntl ├── fcntl.c ├── tst-deadlk.c ├── tst-flock-sj.c ├── tst-flock2.c └── tst-flock3.c ├── lend ├── .gitignore ├── COPYING ├── Makefile ├── README.md ├── ld32.c ├── ld32.h └── ld32test.c ├── libcx-stats.c ├── libcx.def ├── libcx ├── handles.c ├── interrupt.c ├── libcx │ └── handles.h └── tst-handles.c ├── main.c ├── main.s ├── mmap ├── mmap.c ├── mmap.h ├── sys │ └── mman.h ├── tst-anon_mmap.c ├── tst-anon_mmap2.c ├── tst-madvise.c ├── tst-mmap.c ├── tst-mmap10.c ├── tst-mmap11.c ├── tst-mmap12.c ├── tst-mmap2.c ├── tst-mmap3.c ├── tst-mmap4.c ├── tst-mmap5.c ├── tst-mmap6.c ├── tst-mmap7.c ├── tst-mmap8.c ├── tst-mmap9.c ├── tst-mprotect.c ├── tst-msync.c ├── tst-msync2.c └── tst-msync3.c ├── net ├── getaddrinfo.c ├── getifaddrs.c ├── if_nameindex.c ├── ifaddrs.h ├── libcx │ └── net.h ├── tst-getaddrinfo.c ├── tst-getifaddrs.c └── tst-nameindex.c ├── poll ├── CHANGELOG.md ├── INSTALL ├── LICENSE ├── Makefile ├── README.md ├── install.sh ├── poll.c ├── poll.h ├── polltest.c └── tst-poll.c ├── pwrite ├── pwrite.c └── tst-pwrite.c ├── select ├── select.c └── tst-select.c ├── shared.c ├── shared.h ├── shmem ├── libcx │ └── shmem.h ├── shmem.c └── tst-shmem.c ├── spawn ├── libcx │ └── spawn2.h ├── spawn2-internal.h ├── spawn2-wrapper.c ├── spawn2.c └── tst-spawn2.c ├── test-skeleton.c ├── tst-fpucw.c ├── tst-shared.c └── version.h /.gitignore: -------------------------------------------------------------------------------- 1 | # test output 2 | test*.log 3 | *-libcx.log 4 | *-exceptq.txt 5 | 6 | # project files 7 | libcx.* 8 | 9 | # ignore out directory for in tree builds 10 | out 11 | -------------------------------------------------------------------------------- /Config.kmk: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Global kBuild project configuration file 3 | 4 | # Grab version number 5 | BUILD_VERSION_FILE := $(PATH_ROOT)/src/version.h 6 | BUILD_VERSION := $(shell $(SED) -nr -e 's/^\#define VERSION_MAJOR[[:space:]]+([0-9][0-9a-z]*).*$$/\1/p' \ 7 | -e 's/^\#define VERSION_MINOR[[:space:]]+([0-9][0-9a-z]*).*$$/\1/p' \ 8 | -e 's/^\#define VERSION_BUILD[[:space:]]+([0-9][0-9a-z]*).*$$/\1/p' \ 9 | < $(BUILD_VERSION_FILE)) 10 | BUILD_VERSION_MAJOR := $(word 1, $(BUILD_VERSION)) 11 | $(if $(BUILD_VERSION_MAJOR),,$(error $(BUILD_VERSION_FILE): Invalid VERSION_MAJOR)) 12 | BUILD_VERSION_MINOR := $(word 2, $(BUILD_VERSION)) 13 | $(if $(BUILD_VERSION_MINOR),,$(error $(BUILD_VERSION_FILE): Invalid VERSION_MINOR)) 14 | BUILD_VERSION_BUILD := $(word 3, $(BUILD_VERSION)) 15 | $(if $(BUILD_VERSION_BUILD),,$(error $(BUILD_VERSION_FILE): Invalid VERSION_BUILD)) 16 | BUILD_VERSION := $(BUILD_VERSION_MAJOR).$(BUILD_VERSION_MINOR).$(BUILD_VERSION_BUILD) 17 | BUILD_VERSION_DEPS = $(BUILD_VERSION_FILE) $(MAKEFILE_LIST) 18 | 19 | # Grab build properties suitable for BLDLEVEL 20 | BUILD_DATE := $(shell LANG=C printf ' %-24.24s ' "`date -u +'%Y-%m-%d %T'`") 21 | BUILD_HOST := $(shell printf '%-.11s' `echo $$HOSTNAME`) 22 | 23 | # Format BLDLEVEL string (excluding the description, may be used as a prefix for it) 24 | BUILD_BLDLEVEL := @\#bww bitwise works GmbH:$(BUILD_VERSION_MAJOR).$(BUILD_VERSION_MINOR)\#@\#\#1\#\#$(BUILD_DATE)$(BUILD_HOST)::::$(BUILD_VERSION_BUILD)::@@ 25 | 26 | # Unix layout: DLLs come to the lib dir. 27 | INST_DLL = $(INST_LIB) 28 | 29 | # Non-standard installation dirs. 30 | INST_INCLUDE ?= include/ 31 | 32 | # Unix-like hard-coded installation prefix (set by e.g. RPM). 33 | ifdef INST_PREFIX 34 | ifneq ($(DESTDIR)$(DESTROOT),) 35 | PATH_INS = $(firstword $(DESTDIR) $(DESTROOT))/$(INST_PREFIX) 36 | else 37 | PATH_INS = $(PATH_OUT)/$(INST_PREFIX) 38 | endif 39 | else 40 | INST_PREFIX = $(PATH_INS) 41 | endif 42 | 43 | # GCC 8 option to strip absolute file paths (both to save space and for safety) 44 | GCC_OPT_STRIP_FILEPATH = \ 45 | -ffile-prefix-map=$(PATH_ROOT)=libcx \ 46 | -ffile-prefix-map=$(PATH_OUT)=libcx \ 47 | -ffile-prefix-map=$(TEMP)=libcx 48 | 49 | # 50 | # Templates 51 | # 52 | 53 | TEMPLATE_C = C sources 54 | TEMPLATE_C_TOOL = GCC3OMF 55 | # If either CFLAGS or LDFLAGS are set, assume that they configure the build flavor 56 | # (like in case of the RPM build), otherwise set the flavor ourselves. 57 | ifneq ($(strip $(CFLAGS)$(LDFLAGS)),) 58 | TEMPLATE_C_CFLAGS += $(CFLAGS) 59 | TEMPLATE_C_LDFLAGS += $(LDFLAGS) 60 | else 61 | TEMPLATE_C_CFLAGS.release += -g -O2 $(GCC_OPT_STRIP_FILEPATH) 62 | TEMPLATE_C_CFLAGS.debug += -g -O0 -DDEBUG $(GCC_OPT_STRIP_FILEPATH) 63 | TEMPLATE_C_LDFLAGS.release += -g 64 | TEMPLATE_C_LDFLAGS.debug += -g 65 | endif 66 | 67 | ifdef LIBCX_DEV_BUILD 68 | TEMPLATE_C_DEFS += LIBCX_DEV_BUILD 69 | endif 70 | 71 | TEMPLATE_Dll = DLLs 72 | TEMPLATE_Dll_EXTENDS = C 73 | TEMPLATE_Dll_LDFLAGS = -Zhigh-mem 74 | # Create a.out import libraries when installing 75 | TEMPLATE_Dll_POST_INST_CMDS = \ 76 | $$(QUIET)$$(TOOL_GCC3OMF_AR_IMP) $$@ -o $$(@:$(SUFF_DLL)=.a) \ 77 | $$(NL)$$(TAB)$$(QUIET)$$(TOOL_GCC3OMF_AR_IMP) $$@ -o $$(@D)/$(target).a 78 | 79 | TEMPLATE_Util = Utils 80 | TEMPLATE_Util_EXTENDS = C 81 | TEMPLATE_Util_LIBS = $(PATH_STAGE_LIB)/libcx0$(SUFF_LIB) 82 | 83 | TEMPLATE_Test = Tests 84 | TEMPLATE_Test_EXTENDS = C 85 | TEMPLATE_Test_DEFS = _GNU_SOURCE 86 | TEMPLATE_Test_INCS = src/poll src/mmap 87 | TEMPLATE_Test_LIBS = $(PATH_STAGE_LIB)/libcx0$(SUFF_LIB) pthread 88 | 89 | # 90 | # Simple test framework 91 | # 92 | 93 | ALL_TESTS = $(TESTS) $(TESTS.$(KBUILD_TYPE)) 94 | ALL_TARGETS += $(ALL_TESTS) 95 | 96 | ## 97 | # Defines rules for one test. 98 | # $(test) - test source. 99 | # $(target) - test target name. 100 | # 101 | define def_test_rules 102 | 103 | PROGRAMS += $(target) 104 | $(target)_TEMPLATE = Test 105 | $(target)_INCS = $$(abspathex $$(dir $(test)), $$($(test)_DEFPATH)) 106 | $(target)_SOURCES = $$(abspathex $(test), $$($(test)_DEFPATH)) $$(abspathex $($(test)_SOURCES), $$($(test)_DEFPATH)) 107 | 108 | # Note: LIBPATHSTRICT=T doesn't work with posix shells, use cmd.exe. 109 | .PHONY: test-$(target) 110 | test-$(target): 111 | ifneq ($(has_iters),) 112 | $(QUIET)rm -rf test-$(target).log 113 | $(QUIET)for f in `seq 1 $(iters)` ; \ 114 | do \ 115 | echo Running test $(target) [iter $$$$f]... ; \ 116 | LIBCX_TRACE_OUTPUT=curdir LIBC_LOGGING_OUTPUT=curdir \ 117 | BEGINLIBPATH="$(PATH_STAGE_LIB);$(BEGINLIBPATH)" LIBPATHSTRICT=T $(PATH_STAGE_BIN)/$$(notdir $$($(target)_1_TARGET)) --direct >> test-$(target).log 2>&1 || exit $$$$? ; \ 118 | done 119 | else 120 | $(QUIET)echo Running test $(target)... 121 | $(QUIET)LIBCX_TRACE_OUTPUT=curdir LIBC_LOGGING_OUTPUT=curdir \ 122 | BEGINLIBPATH="$(PATH_STAGE_LIB);$(BEGINLIBPATH)" LIBPATHSTRICT=T $(PATH_STAGE_BIN)/$$(notdir $$($(target)_1_TARGET)) --direct > test-$(target).log 2>&1 123 | endif 124 | 125 | ifneq ($(ordered),) 126 | .NOTPARALLEL: test-$(target) 127 | endif 128 | 129 | TESTING += test-$(target) 130 | 131 | endef # def_test_rules 132 | 133 | ## 134 | # Defines one test. 135 | # $(test) - test source. 136 | # 137 | define def_test 138 | local target := $(notdir $(basename $(test))) 139 | local ordered := $($(test)_ORDERED) 140 | local has_iters := 141 | local iters := 1 142 | ifneq ($($(target)_ITERATIONS),) 143 | local has_iters := 1 144 | local iters := $($(target)_ITERATIONS) 145 | endif 146 | $(eval $(def_test_rules)) 147 | endef # def_test 148 | -------------------------------------------------------------------------------- /Makefile.kmk: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Top-level kBuild makefile 3 | # 4 | 5 | SUB_DEPTH = . 6 | include $(KBUILD_PATH)/subheader.kmk 7 | 8 | # 9 | # Include sub-makefiles. 10 | # 11 | 12 | include $(PATH_SUB_CURRENT)/src/Makefile.kmk 13 | 14 | # 15 | # Populate tests for test target. 16 | # 17 | 18 | $(foreach test, $(ALL_TESTS), $(evalvalctx def_test)) 19 | 20 | # 21 | # Special target to clean test results 22 | # 23 | 24 | testclean: 25 | %$(call MSG_L1,Cleaning test products...) 26 | $(QUIET)$(RM) -f -- $(wildcard test-tst*.log) $(wildcard *-libcx.log) $(wildcard *-exceptq.txt) 27 | 28 | test:: testclean 29 | 30 | # 31 | # Special target to clean install results 32 | # (kbuild doesn't do that from clean). 33 | # 34 | 35 | distclean: 36 | %$(call MSG_L1,Cleaning install products...) 37 | $(QUIET)$(RM) -f -- \ 38 | $(_INSTALLS_FILES) 39 | $(QUIET)$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- \ 40 | $(rsort $(_INSTALLS_DIRS)) 41 | 42 | 43 | include $(FILE_KBUILD_SUB_FOOTER) 44 | -------------------------------------------------------------------------------- /src/Makefile.kmk: -------------------------------------------------------------------------------- 1 | ## @file 2 | # kBuild makefile for libcx DLL and tests 3 | # 4 | 5 | SUB_DEPTH = .. 6 | include $(KBUILD_PATH)/subheader.kmk 7 | 8 | # 9 | # Main libcx DLL 10 | # 11 | 12 | DLLS += libcx 13 | 14 | libcx_TEMPLATE = Dll 15 | libcx_NAME = libcx0 # must match libcx.def 16 | libcx_INCS = poll mmap 17 | libcx_SOURCES = \ 18 | fcntl/fcntl.c \ 19 | pwrite/pwrite.c \ 20 | poll/poll.c \ 21 | select/select.c \ 22 | mmap/mmap.c \ 23 | exeinfo/exeinfo.c \ 24 | beginthread.c \ 25 | spawn/spawn2.c \ 26 | net/getaddrinfo.c \ 27 | net/getifaddrs.c \ 28 | net/if_nameindex.c \ 29 | shmem/shmem.c \ 30 | libcx/handles.c \ 31 | libcx/interrupt.c \ 32 | lend/ld32.c \ 33 | main.c \ 34 | main.s \ 35 | shared.c 36 | 37 | # Release definitions 38 | libcx_SOURCES.release += $(PATH_OBJ)/libcx-release.def 39 | 40 | $(PATH_OBJ)/libcx-release.def: $(PATH_SUB_CURRENT)/libcx.def $(BUILD_VERSION_DEPS) | $(call DIRDEP,$(PATH_OBJ)) 41 | $(call MSG_L1,Generating $@) 42 | $(QUIET)cp $< $@ 43 | $(QUIET)echo DESCRIPTION '"$(BUILD_BLDLEVEL)kLIBC Extension Library"' >> $@ 44 | 45 | # Debug definitions 46 | libcx_DEFS.debug = TRACE_ENABLED STATS_ENABLED DEBUG 47 | libcx_SOURCES.debug += $(PATH_OBJ)/libcx-debug.def 48 | 49 | $(PATH_OBJ)/libcx-debug.def: $(PATH_SUB_CURRENT)/libcx.def $(BUILD_VERSION_DEPS) | $(call DIRDEP,$(PATH_OBJ)) 50 | $(call MSG_L1,Generating $@) 51 | $(QUIET)sed -e 's/ ;ddd / /' < $< > $@ 52 | $(QUIET)echo DESCRIPTION '"$(BUILD_BLDLEVEL)kLIBC Extension Library (debug)"' >> $@ 53 | 54 | # Make sure tests & utils inherit libcx debug defs 55 | TEMPLATE_Test_DEFS.debug += $(libcx_DEFS.debug) 56 | TEMPLATE_Util_DEFS.debug += $(libcx_DEFS.debug) 57 | 58 | # 59 | # Utilities 60 | # 61 | 62 | PROGRAMS += libcx-stats 63 | libcx-stats_TEMPLATE = Util 64 | libcx-stats_SOURCES = libcx-stats.c $(PATH_OBJ)/tool.def 65 | 66 | PROGRAMS += libcx-spawn2-wrapper 67 | libcx-spawn2-wrapper_INST = $(INST_DLL)libcx-spawn2.wrp 68 | libcx-spawn2-wrapper_TEMPLATE = Util 69 | libcx-spawn2-wrapper_SOURCES = spawn/spawn2-wrapper.c $(PATH_OBJ)/tool.def 70 | 71 | INSTALLS += libcx-spawn2-wrapper-inst 72 | libcx-spawn2-wrapper_inst_SOURCES = $(libcx-spawn2-wrapper_1_TARGET) 73 | 74 | $(PATH_OBJ)/tool.def: $(BUILD_VERSION_DEPS) | $(call DIRDEP,$(PATH_OBJ)) 75 | $(call MSG_L1,Generating $@) 76 | $(QUIET)echo DESCRIPTION '"$(BUILD_BLDLEVEL)kLIBC Extension Library Tool"' >> $@ 77 | 78 | # 79 | # Tests 80 | # 81 | 82 | TESTS_INCS += poll mmap 83 | 84 | TESTS.debug += tst-shared.c 85 | tst-shared.c_ORDERED = 1 86 | 87 | TESTS += tst-fpucw.c 88 | 89 | TESTS += \ 90 | fcntl/tst-flock2.c \ 91 | fcntl/tst-flock3.c \ 92 | fcntl/tst-flock-sj.c \ 93 | fcntl/tst-deadlk.c 94 | 95 | TESTS += pwrite/tst-pwrite.c 96 | 97 | TESTS += poll/tst-poll.c 98 | 99 | TESTS += select/tst-select.c 100 | 101 | TESTS += \ 102 | mmap/tst-anon_mmap.c \ 103 | mmap/tst-anon_mmap2.c \ 104 | mmap/tst-mmap.c \ 105 | mmap/tst-mmap2.c \ 106 | mmap/tst-mmap3.c \ 107 | mmap/tst-mmap4.c \ 108 | mmap/tst-mmap5.c \ 109 | mmap/tst-mmap6.c \ 110 | mmap/tst-mmap7.c \ 111 | mmap/tst-mmap8.c \ 112 | mmap/tst-mmap9.c \ 113 | mmap/tst-mmap10.c \ 114 | mmap/tst-mmap11.c \ 115 | mmap/tst-mmap12.c \ 116 | mmap/tst-msync.c \ 117 | mmap/tst-msync2.c \ 118 | mmap/tst-msync3.c \ 119 | mmap/tst-madvise.c \ 120 | mmap/tst-mprotect.c 121 | 122 | tst-mmap11_ITERATIONS = 5 123 | 124 | TESTS += exeinfo/tst-exeinfo.c 125 | exeinfo/tst-exeinfo.c_SOURCES = exeinfo/tst-exeinfo.rc 126 | 127 | TESTS += spawn/tst-spawn2.c 128 | 129 | TESTS += \ 130 | net/tst-getaddrinfo.c \ 131 | net/tst-getifaddrs.c \ 132 | net/tst-nameindex.c 133 | 134 | TESTS += shmem/tst-shmem.c 135 | 136 | TESTS += libcx/tst-handles.c 137 | 138 | PROGRAMS += tst-exeinfo-packed-1 139 | tst-exeinfo-packed-1_TEMPLATE = Test 140 | tst-exeinfo-packed-1_SOURCES = exeinfo/tst-exeinfo.c exeinfo/tst-exeinfo.rc 141 | tst-exeinfo-packed-1_POST_CMDS = lxlite $(out) /CS /MR3 /MLN >nul 142 | 143 | PROGRAMS += tst-exeinfo-packed-2 144 | tst-exeinfo-packed-2_TEMPLATE = Test 145 | tst-exeinfo-packed-2_SOURCES = exeinfo/tst-exeinfo.c exeinfo/tst-exeinfo.rc 146 | tst-exeinfo-packed-2_POST_CMDS = lxlite $(out) /CS /MRN /ML1 >nul 147 | 148 | include $(FILE_KBUILD_SUB_FOOTER) 149 | -------------------------------------------------------------------------------- /src/beginthread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _beginthread override for kLIBC. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #define OS2EMX_PLAIN_CHAR 23 | #define INCL_BASE 24 | #include 25 | 26 | #if defined(USE_EXCEPTQ) 27 | #define INCL_LIBLOADEXCEPTQ 28 | #define INCL_FORKEXCEPTQ 29 | #include 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "shared.h" 39 | 40 | /* Defined in main.c */ 41 | extern 42 | ULONG _System libcxExceptionHandler(PEXCEPTIONREPORTRECORD report, 43 | PEXCEPTIONREGISTRATIONRECORD reg, 44 | PCONTEXTRECORD ctx, 45 | PVOID unused); 46 | 47 | struct threaddata 48 | { 49 | void (*start)(void *arg); 50 | void *arg; 51 | }; 52 | 53 | /* Defined in libcx.def */ 54 | extern int _libc_beginthread(void (*start)(void *arg), void *stack, 55 | unsigned stack_size, void *arg_list); 56 | 57 | /* Defined in libcx.def */ 58 | unsigned _libc__control87(unsigned new_cw, unsigned mask); 59 | 60 | /** 61 | * LIBCx thread wrapper. 62 | * 63 | * @param arg Thread function argument. 64 | */ 65 | static void threadWrapper(void *d) 66 | { 67 | /* 68 | * Use an array of registartion records to guarantee their order on the 69 | * stack: DosSetExceptionHandler requires the registration record of an inner 70 | * exception handler to be located deeper on the stack (i.e. have a lower 71 | * address given that the stack grows down) than the registration record of 72 | * an outer one. Note that using nested scopes *does not* guarantee the order 73 | * — the GCC optimizer is free to rearrange variables on the stack. 74 | */ 75 | EXCEPTIONREGISTRATIONRECORD xcptRec[2]; 76 | 77 | #if defined(USE_EXCEPTQ) 78 | /* Install the EXCEPTQ trap generator (outer, higher address) */ 79 | LibLoadExceptq(&xcptRec[1]); 80 | #endif 81 | 82 | /* Install the LIBCx own exception handler for various needs (inner, lower address) */ 83 | xcptRec[0].ExceptionHandler = libcxExceptionHandler; 84 | xcptRec[0].prev_structure = END_OF_CHAIN; 85 | DosSetExceptionHandler(&xcptRec[0]); 86 | 87 | /* Thread data is on the heap, make a copy on the stack and free it */ 88 | struct threaddata data = *(struct threaddata *)d; 89 | free(d); 90 | 91 | /* Save the FPU control word for the exception handler */ 92 | { 93 | unsigned cw = _libc__control87(0, 0); 94 | __libc_TLSSet(gFpuCwTls, (void*)cw); 95 | } 96 | 97 | data.start(data.arg); 98 | 99 | DosUnsetExceptionHandler(&xcptRec[0]); 100 | 101 | #if defined(USE_EXCEPTQ) 102 | UninstallExceptq(&xcptRec[1]); 103 | #endif 104 | } 105 | 106 | /** 107 | * Overrides kLIBC _beginthread to install exception handlers on additional 108 | * threads. 109 | * 110 | * @param start Thread function. 111 | * @param stack Stack pointer. 112 | * @param stack_size Stack size. 113 | * @param arg_list Thread function argument. 114 | * @return Thread ID or -1 on failure. 115 | */ 116 | int _beginthread(void (*start)(void *arg), void *stack, unsigned stack_size, 117 | void *arg_list) 118 | { 119 | struct threaddata *d = (struct threaddata *)malloc(sizeof(*d)); 120 | if (!d) 121 | { 122 | errno = ENOMEM; 123 | return -1; 124 | } 125 | 126 | d->start = start; 127 | d->arg = arg_list; 128 | 129 | int rc = _libc_beginthread(threadWrapper, stack, stack_size, d); 130 | if (rc == -1) 131 | free(d); 132 | 133 | return rc; 134 | } 135 | -------------------------------------------------------------------------------- /src/exeinfo/libcx/exeinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Public exeinfo API. 3 | * Copyright (C) 2017 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2017. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef LIBCX_EXEINFO_H 23 | #define LIBCX_EXEINFO_H 24 | 25 | #include 26 | 27 | /** 28 | * Format of the executable file. 29 | */ 30 | typedef enum _exeinfo_format 31 | { 32 | EXEINFO_FORMAT_UNKNOWN = 0, /**< Unknown executable format. */ 33 | #if 0 /* TODO later */ 34 | EXEINFO_FORMAT_MZ = 1, /**< DOS 16-bit executable. */ 35 | EXEINFO_FORMAT_NE = 2, /**< OS/2 and Windows 16-bit executable. */ 36 | #endif 37 | EXEINFO_FORMAT_LX = 3, /**< OS/2 LX 32-bit executable. */ 38 | 39 | EXEINFO_FORMAT_INVALID = -1, /**< Invalid format (used as error indicator). */ 40 | } 41 | EXEINFO_FORMAT; 42 | 43 | /** 44 | * Resource object of the executable file. 45 | */ 46 | typedef struct _exeinfo_resource 47 | { 48 | int type; 49 | int id; 50 | const char *data; 51 | int size; 52 | } 53 | EXEINFO_RESOURCE; 54 | 55 | /** 56 | * Opaque executable file handle. 57 | * 58 | * Used by the exeinfo API functions to refer to an executable file opened with 59 | * #exeinfo_open(). 60 | */ 61 | typedef struct _exeinfo *EXEINFO; 62 | 63 | __BEGIN_DECLS 64 | 65 | /** 66 | * Opens an executable file and prepares it for reading the file structure. 67 | * 68 | * The file must exist and will be opened in read-only mode. Note that the file 69 | * will remain open until #execinfo_open() is called. 70 | * 71 | * All `execinfo` functions use POSIX error codes to report failures. A special 72 | * meaning is put into EILSEQ which is returned when an error in the executable 73 | * file structure is detected that prevents the requrested operation. Note, 74 | * however, that if the format of the executable file is not recognized by 75 | * the #execinfo_open() call, it will report a success rather than EILSEQ but 76 | * #exeinfo_get_format() will return EXEINFO_FORMAT_UNKNOWN in this case. This 77 | * is because there are `execinfo` functions that don't require a particular 78 | * format and may work with any existing file. 79 | * 80 | * @param fname Executable file name. 81 | * @return An opaque file handle on success or NULL on failure. Sets @c errno 82 | * to a POSIX error code if NULL is returned. 83 | */ 84 | EXEINFO exeinfo_open(const char *fname); 85 | 86 | /** 87 | * Returns the format of the executable file. 88 | * 89 | * @param info Handle to the executable file returned by #exeinfo_open(). 90 | * @return One of EXEINFO_FORMAT values or EXEINFO_FORMAT_INVALID on failure. 91 | * Sets @c errno to a POSIX error code if EXEINFO_FORMAT_INVALID is returned. 92 | */ 93 | EXEINFO_FORMAT exeinfo_get_format(EXEINFO info); 94 | 95 | /* TODO later 96 | EXEINFO_RESOURCE *exeinfo_find_first_resource(EXEINFO info, int type); 97 | EXEINFO_RESOURCE *exeinfo_find_next_resource(EXEINFO info); 98 | */ 99 | 100 | /** 101 | * Returns a pointer to the requested resource object's data. 102 | * 103 | * Valid resource type values are from 1 to 0xFFFE. Values from 1 to 255 are 104 | * reserved for predefinition. Values greater tthan 255 are user-defined 105 | * resource types. Well-known predefined resource types are accessible via RT_* 106 | * constants from . Valid resource identifier values are from 1 to 107 | * 0xFFFE. 108 | * 109 | * The returned data buffer is read-only and its size corresponds to the return 110 | * value of this function. The pointer to this data buffer is valid until 111 | * #exeinfo_close() is called on the associated executable file handle. If 112 | * access to the data buffer is needed after calling #exeinfo_close(), its 113 | * contents should be copied to a user buffer prior to this call. 114 | * 115 | * If @a data is NULL, only the size of the requested resource object's data 116 | * is returned. Note that the object's data itself is not accessed in this case 117 | * so a subsequent call with a non-NULL argument may fail with EILSEQ or ENOMEM. 118 | * 119 | * If the requested resource is not found in the given executable file, this 120 | * function returns -1 and sets @c errno to ENOENT. 121 | * 122 | * @note See `DosGetResource` in CPREF for more information about predefined 123 | * resource types. 124 | * 125 | * @param info Handle to the executable file returned by #exeinfo_open(). 126 | * @param type Resource type. 127 | * @param id Resource identifier. 128 | * @param data Address of a variable to receive a pointer to the resource data. 129 | * @return Size of the data buffer returned in @a data, in bytes or -1 on 130 | * failure. Sets @c errno to a POSIX error code if -1 is returned. 131 | */ 132 | int exeinfo_get_resource_data(EXEINFO info, int type, int id, const char **data); 133 | 134 | /** 135 | * Closes the executable file opened with #exeinfo_open() and releases system 136 | * resources allocated for reading the file structure. 137 | * 138 | * @param info Handle to the executable file returned by #exeinfo_open(). 139 | * @return 0 on success and -1 on failure. Sets @c errno to a POSIX error code 140 | * if -1 is returned. 141 | */ 142 | int exeinfo_close(EXEINFO info); 143 | 144 | __END_DECLS 145 | 146 | #endif /* LIBCX_EXEINFO_H */ 147 | -------------------------------------------------------------------------------- /src/exeinfo/tst-exeinfo-rc.h: -------------------------------------------------------------------------------- 1 | #define ID_1 1 2 | #define ID_1_DATA "rc_data_1" 3 | 4 | #define ID_2 9999 5 | #define ID_2_DATA "@#Vendor:1.0#@##1## 1 Jan 2000 00:00:00 myhost::en::1::@@My Test Software" 6 | 7 | #define ID_NON_EXISTENT 111 8 | -------------------------------------------------------------------------------- /src/exeinfo/tst-exeinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for exeinfo API. 3 | * Copyright (C) 2017 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2017. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include "libcx/exeinfo.h" 30 | 31 | #include "tst-exeinfo-rc.h" 32 | 33 | static int do_test(void); 34 | #define TEST_FUNCTION do_test() 35 | #include "../test-skeleton.c" 36 | 37 | static int do_test(void) 38 | { 39 | char fname[PATH_MAX + 16 /* "packed-N */]; 40 | if (_execname(fname, PATH_MAX) == -1) 41 | perrno_and(return 1, "_execname"); 42 | 43 | char *fext = _getext(fname); 44 | if (!fext) 45 | perrno_and(return 1, "_getext"); 46 | 47 | EXEINFO info; 48 | EXEINFO_FORMAT fmt; 49 | 50 | int i; 51 | int len; 52 | const char *data; 53 | 54 | for (i = 1; i <= 3; ++i) 55 | { 56 | if (i == 2) 57 | strcpy(fext, "-packed-1.exe"); 58 | else if (i == 3) 59 | strcpy(fext, "-packed-2.exe"); 60 | 61 | printf("Test %d.open\n", i); 62 | 63 | info = exeinfo_open(fname); 64 | if (!info) 65 | perrno_and(return 1, "exeinfo_open"); 66 | 67 | fmt = exeinfo_get_format(info); 68 | if (fmt != EXEINFO_FORMAT_LX) 69 | perr_and(return 1, "exeinfo_get_format is %d and not EXEINFO_FORMAT_LX (%d)", 70 | fmt, EXEINFO_FORMAT_LX); 71 | 72 | printf("Test %d.1\n", i); 73 | 74 | len = exeinfo_get_resource_data (info, RT_RCDATA, ID_NON_EXISTENT, &data); 75 | if (len != -1 || errno != ENOENT) 76 | perr_and(return 1, 77 | "exeinfo_get_resource_data(RT_RCDATA, %d) shoud fail with -1 and ENOENT (%d) " 78 | "but it returns %d and errno %d", 79 | ID_NON_EXISTENT, ENOENT, len, errno); 80 | 81 | printf("Test %d.2\n", i); 82 | 83 | len = exeinfo_get_resource_data (info, RT_RCDATA, ID_1, &data); 84 | if (len == -1) 85 | perrno_and(return 1, "exeinfo_get_resource_data"); 86 | if (len != sizeof(ID_1_DATA)) 87 | perr_and(return 1, "ID_1_DATA size should be %d, got %d", sizeof(ID_1_DATA), len); 88 | if (strncmp(data, ID_1_DATA, len) != 0) 89 | perr_and(return 1, "ID_1 data should be [%s], got [%s]", ID_1_DATA, data); 90 | 91 | printf("Test %d.3\n", i); 92 | 93 | len = exeinfo_get_resource_data (info, RT_RCDATA, ID_2, &data); 94 | if (len == -1) 95 | perrno_and(return 1, "exeinfo_get_resource_data"); 96 | if (len != sizeof(ID_2_DATA)) 97 | perr_and(return 1, "ID_2_DATA size should be %d, got %d", sizeof(ID_2_DATA), len); 98 | if (strncmp(data, ID_2_DATA, len) != 0) 99 | perr_and(return 1, "ID_2 data should be [%s], got [%s]", ID_2_DATA, data); 100 | 101 | printf("Test %d.close\n", i); 102 | 103 | if (exeinfo_close(info) == -1) 104 | perrno_and(return 1, "exeinfo_close"); 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /src/exeinfo/tst-exeinfo.rc: -------------------------------------------------------------------------------- 1 | #include "tst-exeinfo-rc.h" 2 | 3 | RCDATA ID_1 { ID_1_DATA } 4 | RCDATA ID_2 { ID_2_DATA } 5 | 6 | 7 | /* Make sure we're big enough for lxlite to pack data with both EXEPACK1 and EXEPACK2 */ 8 | RCDATA 0xFFF0 { "garbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbage" 9 | "garbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbage" } 10 | RCDATA 0xFFF1 { "garbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbage" 11 | "garbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbagegarbage" } 12 | -------------------------------------------------------------------------------- /src/fcntl/tst-deadlk.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2016 bww bitwise works GmbH. 2 | This file is part of the kLIBC Extension Library. 3 | Authored by Dmitry Kuminov , 2016. 4 | 5 | The kLIBC Extension Library is free software; you can redistribute it 6 | and/or modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | The kLIBC Extension Library is distributed in the hope that it will be 11 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with the GNU C Library; if not, see 17 | . */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /* This test case is roughly based on this snippet: 28 | http://stackoverflow.com/questions/27694721/why-dont-i-see-deadlock-edeadlk-when-several-processes-lock-the-same-fd-with */ 29 | 30 | static int do_test(void); 31 | #define TEST_FUNCTION do_test() 32 | #include "../test-skeleton.c" 33 | 34 | static int 35 | do_test (void) 36 | { 37 | int fd = create_temp_file("tst-deadlk-", NULL); 38 | if (fd == -1) 39 | { 40 | puts ("create_temp_file failed"); 41 | return 1; 42 | } 43 | 44 | pid_t pid1, pid2; 45 | 46 | struct flock fl; 47 | 48 | fl.l_type = F_WRLCK; 49 | fl.l_whence = SEEK_SET; 50 | fl.l_start = 0; 51 | fl.l_len = 2; /* lock "doors" (i.e. bytes) 0 and 1 */ 52 | 53 | if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK,&fl)) == -1) 54 | { 55 | perror ("fcntl failed"); 56 | return 1; 57 | } 58 | 59 | if ((pid1 = fork ())) 60 | { 61 | /* parent */ 62 | if ((pid2 = fork ())) 63 | { 64 | /* still parent */ 65 | fl.l_type = F_UNLCK; 66 | fl.l_len = 2; /* unlock both doors: let the fun begin :-) */ 67 | 68 | sleep (2); 69 | 70 | printf("Parent %d is unlocking lock...\n", getpid()); 71 | if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) == -1) 72 | { 73 | perror ("fcntl failed"); 74 | return 1; 75 | } 76 | 77 | int status1, status2; 78 | 79 | if (TEMP_FAILURE_RETRY (waitpid (pid1, &status1, 0)) != pid1) 80 | { 81 | perror ("waitpid failed"); 82 | return 1; 83 | } 84 | if (TEMP_FAILURE_RETRY (waitpid (pid2, &status2, 0)) != pid2) 85 | { 86 | perror ("waitpid failed"); 87 | return 1; 88 | } 89 | 90 | return status1 ? status1 : status2 ? status2 : 0; 91 | } 92 | } 93 | 94 | if (pid1 == -1 || pid2 == -1) 95 | { 96 | perror ("fork failed"); 97 | return 1; 98 | } 99 | 100 | if (!pid1 || !pid2) 101 | { 102 | /* in child 1 or child 2 */ 103 | printf("Child %d started\n", getpid()); 104 | 105 | int offset0 = (pid1 ? 0 : 1); /* child1 gets 0 and 1, child 2 gets 1 and 0 */ 106 | int offset1 = (pid1 ? 1 : 0); 107 | fl.l_len = 1; 108 | 109 | fl.l_start = offset0; /* lock door 0 (1) as soon as parent lets us*/ 110 | printf("Child %d locking byte %d...\n", getpid(), offset0); 111 | if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW,&fl) == -1)) 112 | { 113 | printf ("Child %d fcntl failed (%s)", getpid(), strerror (errno)); 114 | return errno == EDEADLK ? 0 : 1; 115 | } 116 | 117 | sleep (1); /* guarantee that the other child has our next door locked ... */ 118 | 119 | printf("Child %d locking byte %d...\n", getpid(), offset1); 120 | fl.l_start = offset1; /* lock door 1 (0). The second of both children who gets here closes the circle and faces deadlock */ 121 | if (TEMP_FAILURE_RETRY (fcntl(fd, F_SETLKW,&fl) == -1)) 122 | { 123 | printf ("Child %d fcntl failed (%s)\n", getpid(), strerror (errno)); 124 | return errno == EDEADLK ? 0 : 1; 125 | } 126 | 127 | printf("Child %d terminating (and releasing its lock)\n", getpid()); /* Falling off the end of main() will release the lock anyway */ 128 | } 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /src/fcntl/tst-flock-sj.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for fcntl advisory locking split/join logic. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | static int do_test(void); 28 | #define TEST_FUNCTION do_test() 29 | #include "../test-skeleton.c" 30 | 31 | static const char *fl_type_str(short type) 32 | { 33 | return type == F_WRLCK ? "F_WRLCK" : 34 | type == F_RDLCK ? "F_RDLCK" : 35 | type == F_UNLCK ? "F_UNLCK" : "???"; 36 | } 37 | 38 | static void set_lock(int fd, off_t start, off_t len, short type) 39 | { 40 | struct flock fl; 41 | fl.l_start = start; 42 | fl.l_len = len; 43 | fl.l_type = type; 44 | fl.l_whence = SEEK_SET; 45 | 46 | printf("Locking fd %d, region %lld:%lld, type %s\n", fd, start, len, fl_type_str(type)); 47 | 48 | if (TEMP_FAILURE_RETRY(fcntl(fd, F_SETLKW, &fl)) != 0) 49 | { 50 | perror("fcntl(F_SETLKW) failed"); 51 | exit(1); 52 | } 53 | } 54 | 55 | static void check_lock_fn(int fd, off_t start, off_t len, short type, int line) 56 | { 57 | struct flock fl; 58 | 59 | /* This uses the LIBCx-specific extension of passing -1 in l_type to request 60 | * the existing lock at the given position -- this extension is intended to be 61 | * used only for the purposes of this test case */ 62 | fl.l_whence = SEEK_SET; 63 | fl.l_type = -1; 64 | fl.l_start = start; 65 | fl.l_len = 1; 66 | 67 | if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETLK, &fl)) != 0) 68 | { 69 | perror("fcntl(F_GETLK) failed"); 70 | exit(1); 71 | } 72 | 73 | if (fl.l_start != start) 74 | { 75 | printf("line #%d: start: expected %lld, got %lld\n", line, start, fl.l_start); 76 | printf("(region %lld:%lld, type %s)\n", fl.l_start, fl.l_len, fl_type_str(fl.l_type)); 77 | exit(1); 78 | } 79 | 80 | if (fl.l_len != len) 81 | { 82 | printf("line #%d: len: expected %lld, got %lld\n", line, len, fl.l_len); 83 | printf("(region %lld:%lld, type %s)\n", fl.l_start, fl.l_len, fl_type_str(fl.l_type)); 84 | exit(1); 85 | } 86 | 87 | if (fl.l_type != type) 88 | { 89 | printf("line #%d: type: expected %s, got %s\n", line, fl_type_str(type), fl_type_str(fl.l_type)); 90 | printf("(region %lld:%lld, type %s)\n", fl.l_start, fl.l_len, fl_type_str(fl.l_type)); 91 | exit(1); 92 | } 93 | } 94 | 95 | #define check_lock(fd, start, len, type) check_lock_fn(fd, start, len, type, __LINE__) 96 | 97 | static int do_test(void) 98 | { 99 | int fd; 100 | struct flock fl; 101 | char *tmp; 102 | 103 | fd = create_temp_file("tst-flock-sj-", &tmp); 104 | if (fd == -1) 105 | { 106 | perror("create_temp_file failed"); 107 | return 1; 108 | } 109 | 110 | /* split: 111 | * ............... 112 | * WWWWW 113 | * .....WWWWW..... 114 | */ 115 | set_lock(fd, 10, 5, F_WRLCK); 116 | check_lock(fd, 0, 10, F_UNLCK); 117 | check_lock(fd, 10, 5, F_WRLCK); 118 | check_lock(fd, 15, 0, F_UNLCK); 119 | 120 | /* downgrade: 121 | * .....WWWWW..... 122 | * RRRRR 123 | * .....RRRRR..... 124 | */ 125 | set_lock(fd, 10, 5, F_RDLCK); 126 | check_lock(fd, 0, 10, F_UNLCK); 127 | check_lock(fd, 10, 5, F_RDLCK); 128 | check_lock(fd, 15, 0, F_UNLCK); 129 | 130 | /* simple lock remove */ 131 | set_lock(fd, 10, 5, F_UNLCK); 132 | check_lock(fd, 0, 0, F_UNLCK); 133 | 134 | /* split: 135 | * .....WWWWW..... 136 | * RRR 137 | * .....RRRWW..... 138 | */ 139 | set_lock(fd, 10, 5, F_WRLCK); 140 | set_lock(fd, 10, 3, F_RDLCK); 141 | check_lock(fd, 0, 10, F_UNLCK); 142 | check_lock(fd, 10, 3, F_RDLCK); 143 | check_lock(fd, 13, 2, F_WRLCK); 144 | check_lock(fd, 15, 0, F_UNLCK); 145 | 146 | /* reset */ 147 | set_lock(fd, 0, 0, F_UNLCK); 148 | check_lock(fd, 0, 0, F_UNLCK); 149 | 150 | /* split: 151 | * .....WWWWW..... 152 | * RRR 153 | * .....WWRRR..... 154 | */ 155 | set_lock(fd, 10, 5, F_WRLCK); 156 | set_lock(fd, 12, 3, F_RDLCK); 157 | check_lock(fd, 0, 10, F_UNLCK); 158 | check_lock(fd, 10, 2, F_WRLCK); 159 | check_lock(fd, 12, 3, F_RDLCK); 160 | check_lock(fd, 15, 0, F_UNLCK); 161 | 162 | /* reset */ 163 | set_lock(fd, 0, 0, F_UNLCK); 164 | check_lock(fd, 0, 0, F_UNLCK); 165 | 166 | /* split: 167 | * .....WWWWW..... 168 | * RRR 169 | * .....WRRRW..... 170 | */ 171 | set_lock(fd, 10, 5, F_WRLCK); 172 | set_lock(fd, 11, 3, F_RDLCK); 173 | check_lock(fd, 0, 10, F_UNLCK); 174 | check_lock(fd, 10, 1, F_WRLCK); 175 | check_lock(fd, 11, 3, F_RDLCK); 176 | check_lock(fd, 14, 1, F_WRLCK); 177 | check_lock(fd, 15, 0, F_UNLCK); 178 | 179 | /* reset */ 180 | set_lock(fd, 0, 0, F_UNLCK); 181 | check_lock(fd, 0, 0, F_UNLCK); 182 | 183 | /* split: 184 | * .....WWWWW..... 185 | * RRR 186 | * .....WWWWRRR... 187 | */ 188 | set_lock(fd, 10, 5, F_WRLCK); 189 | set_lock(fd, 14, 3, F_RDLCK); 190 | check_lock(fd, 0, 10, F_UNLCK); 191 | check_lock(fd, 10, 4, F_WRLCK); 192 | check_lock(fd, 14, 3, F_RDLCK); 193 | check_lock(fd, 17, 0, F_UNLCK); 194 | 195 | /* reset */ 196 | set_lock(fd, 0, 0, F_UNLCK); 197 | check_lock(fd, 0, 0, F_UNLCK); 198 | 199 | /* join: 200 | * .....RRRWW..... 201 | * RR 202 | * .....RRRRR..... 203 | */ 204 | set_lock(fd, 10, 3, F_RDLCK); 205 | set_lock(fd, 13, 2, F_WRLCK); 206 | set_lock(fd, 13, 2, F_RDLCK); 207 | check_lock(fd, 0, 10, F_UNLCK); 208 | check_lock(fd, 10, 5, F_RDLCK); 209 | check_lock(fd, 15, 0, F_UNLCK); 210 | 211 | /* join: 212 | * .....RRRRR..... 213 | * ... 214 | * .. 215 | * . 216 | * ............... 217 | */ 218 | set_lock(fd, 11, 3, F_UNLCK); 219 | set_lock(fd, 10, 2, F_UNLCK); 220 | check_lock(fd, 0, 14, F_UNLCK); 221 | check_lock(fd, 14, 1, F_RDLCK); 222 | check_lock(fd, 15, 0, F_UNLCK); 223 | set_lock(fd, 14, 1, F_UNLCK); 224 | check_lock(fd, 0, 0, F_UNLCK); 225 | 226 | /* join: 227 | * .....R.R.R..... 228 | * WWWWWWW 229 | * ....WWWWWWW.... 230 | */ 231 | set_lock(fd, 10, 1, F_RDLCK); 232 | set_lock(fd, 12, 1, F_RDLCK); 233 | set_lock(fd, 14, 1, F_RDLCK); 234 | set_lock(fd, 9, 7, F_WRLCK); 235 | check_lock(fd, 0, 9, F_UNLCK); 236 | check_lock(fd, 9, 7, F_WRLCK); 237 | check_lock(fd, 16, 0, F_UNLCK); 238 | 239 | /* @todo Add another process for 'r' test cases */ 240 | 241 | /* 242 | * Close the file (should remove all locks) 243 | */ 244 | 245 | close(fd); 246 | 247 | pid_t pid = fork(); 248 | if (pid == -1) 249 | { 250 | perror("fork failed"); 251 | return 1; 252 | } 253 | 254 | if (pid == 0) 255 | { 256 | /* Child */ 257 | 258 | /* Reopen the closed file */ 259 | fd = open(tmp, O_RDWR); 260 | if (fd == -1) 261 | { 262 | perror("create_temp_file failed"); 263 | return 1; 264 | } 265 | 266 | struct flock fl; 267 | fl.l_start = 9; 268 | fl.l_len = 7; 269 | fl.l_type = F_WRLCK; 270 | fl.l_whence = SEEK_SET; 271 | 272 | printf("Child locking fd %d, region %lld:%lld, type %s\n", fd, fl.l_start, fl.l_len, 273 | fl_type_str(fl.l_type)); 274 | 275 | if (TEMP_FAILURE_RETRY(fcntl(fd, F_SETLK, &fl)) == -1) 276 | { 277 | perror("child fcntl(F_SETLK) failed"); 278 | exit(1); 279 | } 280 | 281 | exit(0); 282 | } 283 | 284 | /* Parent */ 285 | 286 | int status; 287 | if (TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) != pid) 288 | { 289 | perror("waitpid failed"); 290 | return 1; 291 | } 292 | 293 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 294 | { 295 | puts("child terminated abnormally or with error"); 296 | return 1; 297 | } 298 | 299 | return 0; 300 | } 301 | -------------------------------------------------------------------------------- /src/fcntl/tst-flock3.c: -------------------------------------------------------------------------------- 1 | /* test whether fcntl locking works on this system */ 2 | 3 | /* Borrowed from Samba4 configure tests and aligned to build with LIBCx. */ 4 | 5 | #define HAVE_UNISTD_H 6 | #define HAVE_FCNTL_H 7 | #define HAVE_SYS_FCNTL_H 8 | #define HAVE_SYS_WAIT_H 9 | #define HAVE_WAITPID 10 | #define LIBCX_BUILD 11 | 12 | static int do_test(void); 13 | #define TEST_FUNCTION do_test() 14 | #include "../test-skeleton.c" 15 | 16 | #if defined(HAVE_UNISTD_H) 17 | #include 18 | #endif 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef HAVE_FCNTL_H 25 | #include 26 | #endif 27 | 28 | #ifdef HAVE_SYS_FCNTL_H 29 | #include 30 | #endif 31 | 32 | #ifdef HAVE_SYS_WAIT_H 33 | #include 34 | #endif 35 | 36 | #include 37 | 38 | static int sys_waitpid(pid_t pid,int *status,int options) 39 | { 40 | #ifdef HAVE_WAITPID 41 | return waitpid(pid,status,options); 42 | #else /* USE_WAITPID */ 43 | return wait4(pid, status, options, NULL); 44 | #endif /* USE_WAITPID */ 45 | } 46 | 47 | #ifdef LIBCX_BUILD 48 | #define DATA fname 49 | #else 50 | #define DATA "conftest.fcntl" 51 | #endif 52 | 53 | #ifndef SEEK_SET 54 | #define SEEK_SET 0 55 | #endif 56 | 57 | /* lock a byte range in a open file */ 58 | static int do_test(void) 59 | { 60 | struct flock lock; 61 | int fd, ret, status=1; 62 | pid_t pid; 63 | #ifdef LIBCX_BUILD 64 | char *fname; 65 | 66 | fd = create_temp_file("tst-flock3-", &fname); 67 | if (fd == -1) 68 | return -1; 69 | close(fd); 70 | #else 71 | char *testdir = NULL; 72 | 73 | testdir = getenv("TESTDIR"); 74 | if (testdir) chdir(testdir); 75 | #endif 76 | 77 | alarm(10); 78 | 79 | if (!(pid=fork())) { 80 | sleep(2); 81 | fd = open(DATA, O_RDONLY); 82 | 83 | if (fd == -1) { 84 | fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n", 85 | DATA, (int)errno); 86 | exit(1); 87 | } 88 | 89 | lock.l_type = F_WRLCK; 90 | lock.l_whence = SEEK_SET; 91 | lock.l_start = 0x100000000LL; 92 | lock.l_len = 4; 93 | lock.l_pid = getpid(); 94 | 95 | lock.l_type = F_WRLCK; 96 | 97 | /* check if a lock applies */ 98 | ret = fcntl(fd,F_GETLK,&lock); 99 | 100 | if ((ret == -1) || 101 | (lock.l_type == F_UNLCK)) { 102 | fprintf(stderr,"ERROR: lock test failed (ret=%d errno=%d)\n", ret, (int)errno); 103 | exit(1); 104 | } else { 105 | exit(0); 106 | } 107 | } 108 | 109 | unlink(DATA); 110 | fd = open(DATA, O_RDWR|O_CREAT|O_EXCL, 0600); 111 | 112 | if (fd == -1) { 113 | fprintf(stderr,"ERROR: failed to open %s (errno=%d)\n", 114 | DATA, (int)errno); 115 | exit(1); 116 | } 117 | 118 | lock.l_type = F_WRLCK; 119 | lock.l_whence = SEEK_SET; 120 | lock.l_start = 0; 121 | lock.l_len = 0x100000004LL; 122 | lock.l_pid = getpid(); 123 | 124 | /* set a 100000004 byte write lock, should conflict with the above */ 125 | ret = fcntl(fd,F_SETLK,&lock); 126 | 127 | sys_waitpid(pid, &status, 0); 128 | 129 | #ifndef LIBCX_BUILD 130 | unlink(DATA); 131 | #endif 132 | 133 | if (ret != 0) { 134 | fprintf(stderr,"ERROR: failed to lock %s (errno=%d)\n", 135 | DATA, (int)errno); 136 | exit(1); 137 | } 138 | 139 | if (lock.l_len < 0x100000004LL) { 140 | fprintf(stderr,"ERROR: settign lock overflowed\n"); 141 | exit(1); 142 | } 143 | 144 | #if defined(WIFEXITED) && defined(WEXITSTATUS) 145 | if(WIFEXITED(status)) { 146 | status = WEXITSTATUS(status); 147 | } else { 148 | status = 1; 149 | } 150 | #else /* defined(WIFEXITED) && defined(WEXITSTATUS) */ 151 | status = (status == 0) ? 0 : 1; 152 | #endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */ 153 | 154 | if (status) { 155 | fprintf(stderr,"ERROR: lock test failed with status=%d\n", 156 | status); 157 | } 158 | 159 | exit(status); 160 | } 161 | -------------------------------------------------------------------------------- /src/lend/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | ld32test 3 | ld32test.exe 4 | -------------------------------------------------------------------------------- /src/lend/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for x86 Length Disassembler. 2 | # Copyright (C) 2013 Byron Platt 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | #CC=x86_64-w64-mingw32-gcc 18 | 19 | # the -m32 is just for the test program 20 | CFLAGS=-m32 -Wall -ansi -Os 21 | LDFLAGS=-m32 22 | 23 | SRCS=$(wildcard *.c) 24 | OBJS=$(SRCS:.c=.o) 25 | 26 | ld32test: $(OBJS) 27 | 28 | clean: 29 | rm -f $(OBJS) 30 | -------------------------------------------------------------------------------- /src/lend/README.md: -------------------------------------------------------------------------------- 1 | lend 2 | ==== 3 | 4 | Tiny x86 Length Disassembler 5 | 6 | The inspiration for the design of this x86 length disassembler came from 7 | Zdisasm by Z0MBiE (I can't actually find this on his page but it's around, 8 | just google code search for zdisasm.h) and three ideas presented nicely in a 9 | single forum thread: 10 | 11 | http://www.devmaster.net/forums/showthread.php?t=2311 12 | 13 | The three ideas came from the following posts: 14 | 15 | 1. The original post by Nick (a purely logical length disassembler) 16 | 2. The post by earlnsk (a Russian switch case length disassembler) 17 | The Russian length disassembler can be found here: 18 | http://hack-expo.void.ru/groups/blt/text/disasm.txt (Russian) 19 | http://z0mbie.daemonlab.org/disasme.txt (English) 20 | 3. The post by WolfgangSt (bitmap lookup tables) 21 | 22 | With these ideas I decided to make a tiny length disassemler in c. 23 | 24 | My length disassembler can use logical statements or lookup tables (32 byte 25 | bitmap tables) to perform the checks required to determine instruction length. 26 | Currently the smallest footprint I have managed is 589 bytes (LengthDisasm 27 | function length + 4x32 byte lookup tables). I'm sure there are further 28 | optimizations possible (even without using assembly). 29 | 30 | I haven't looked into it too much but I don't think it would to too difficult 31 | to adapt this approach for x86_64. 32 | -------------------------------------------------------------------------------- /src/lend/ld32.c: -------------------------------------------------------------------------------- 1 | /* 2 | x86 Length Disassembler. 3 | Copyright (C) 2013 Byron Platt 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "ld32.h" 20 | 21 | /* length_disasm */ 22 | unsigned int length_disasm(void * opcode0) { 23 | 24 | unsigned char* opcode = opcode0; 25 | 26 | unsigned int flag = 0; 27 | unsigned int ddef = 4, mdef = 4; 28 | unsigned int msize = 0, dsize = 0; 29 | 30 | unsigned char op, modrm, mod, rm; 31 | 32 | prefix: 33 | op = *opcode++; 34 | 35 | /* prefix */ 36 | if (CHECK_PREFIX(op)) { 37 | if (CHECK_PREFIX_66(op)) ddef = 2; 38 | else if (CHECK_PREFIX_67(op)) mdef = 2; 39 | goto prefix; 40 | } 41 | 42 | /* two byte opcode */ 43 | if (CHECK_0F(op)) { 44 | op = *opcode++; 45 | if (CHECK_MODRM2(op)) flag++; 46 | if (CHECK_DATA12(op)) dsize++; 47 | if (CHECK_DATA662(op)) dsize += ddef; 48 | } 49 | 50 | /* one byte opcode */ 51 | else { 52 | if (CHECK_MODRM(op)) flag++; 53 | if (CHECK_TEST(op) && !(*opcode & 0x38)) dsize += (op & 1) ? ddef : 1; 54 | if (CHECK_DATA1(op)) dsize++; 55 | if (CHECK_DATA2(op)) dsize += 2; 56 | if (CHECK_DATA66(op)) dsize += ddef; 57 | if (CHECK_MEM67(op)) msize += mdef; 58 | } 59 | 60 | /* modrm */ 61 | if (flag) { 62 | modrm = *opcode++; 63 | mod = modrm & 0xc0; 64 | rm = modrm & 0x07; 65 | if (mod != 0xc0) { 66 | if (mod == 0x40) msize++; 67 | if (mod == 0x80) msize += mdef; 68 | if (mdef == 2) { 69 | if ((mod == 0x00) && (rm == 0x06)) msize += 2; 70 | } else { 71 | if (rm == 0x04) rm = *opcode++ & 0x07; 72 | if (rm == 0x05 && mod == 0x00) msize += 4; 73 | } 74 | } 75 | } 76 | 77 | opcode += msize + dsize; 78 | 79 | return opcode - (unsigned char *)opcode0; 80 | } 81 | -------------------------------------------------------------------------------- /src/lend/ld32test.c: -------------------------------------------------------------------------------- 1 | /* 2 | x86 Length Disassembler test. 3 | Copyright (C) 2013 Byron Platt 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "ld32.h" 23 | 24 | /* how many opcodes should we length disassemble */ 25 | #define OPCODES 10 26 | 27 | int main(void) { 28 | 29 | int i; 30 | void *opcode; 31 | unsigned int length; 32 | 33 | for (i=0, opcode=main; i, 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include "shared.h" 23 | 24 | int main() 25 | { 26 | print_stats(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/libcx.def: -------------------------------------------------------------------------------- 1 | LIBRARY libcx0 INITINSTANCE TERMINSTANCE 2 | DATA MULTIPLE 3 | EXPORTS 4 | "_fcntl" 5 | "_pwrite" 6 | "_pread" 7 | "_poll" 8 | "_select" 9 | "_close" 10 | "_mmap" 11 | "_munmap" 12 | "_msync" 13 | "_madvise" 14 | "_posix_madvise" 15 | "_mprotect" 16 | "___init_app" 17 | "__beginthread" 18 | "_read" 19 | "___read" 20 | "__stream_read" 21 | "_fread" 22 | "DosRead" 23 | "_ftruncate" 24 | "_exeinfo_open" 25 | "_exeinfo_get_format" 26 | "_exeinfo_get_resource_data" 27 | "_exeinfo_close" 28 | "_spawn2" 29 | "_getaddrinfo" 30 | "_freeaddrinfo" 31 | "_getnameinfo" 32 | "_gai_strerror" 33 | "_getifaddrs" 34 | "_freeifaddrs" 35 | "_if_nameindex" 36 | "_if_freenameindex" 37 | "_if_indextoname" 38 | "_if_nametoindex" 39 | "_wait" 40 | "_wait3" 41 | "_wait4" 42 | "_waitid" 43 | "_waitpid" 44 | "___waitpid" 45 | "DosWaitChild" 46 | "_shmem_create" 47 | "_shmem_give" 48 | "_shmem_open" 49 | "_shmem_duplicate" 50 | "_shmem_close" 51 | "_shmem_map" 52 | "_shmem_unmap" 53 | "_shmem_get_info" 54 | "_shmem_max_handles" 55 | "_libcx_send_handles" 56 | "_libcx_take_handles" 57 | ; private symbols (may disappear w/o any notice) 58 | "_print_stats" @60000 NONAME 59 | "_libcx_assert" @60001 NONAME 60 | ; debug symbols (absent from release builds) 61 | ;ddd "_gpData" 62 | ;ddd "_global_lock" 63 | ;ddd "_global_unlock" 64 | ;ddd "_global_alloc" 65 | ;ddd "_force_libcx_term" 66 | ;ddd "_force_libcx_init" 67 | ;ddd "_set_mmap_full_size" 68 | ;ddd "_get_proc_mmaps" 69 | ;ddd "_libcx_trace" 70 | IMPORTS 71 | __libc__init_app=libcn0.___init_app 72 | __libc_beginthread=libcn0.__beginthread 73 | __libc__read=libcn0.___read 74 | __libc_stream_read=libcn0.__stream_read 75 | __libc__control87=libcn0.__control87 76 | __libc___waitpid=libcn0.___waitpid 77 | _doscalls_DosRead=doscalls.281 78 | _doscalls_DosWaitChild=doscalls.280 79 | -------------------------------------------------------------------------------- /src/libcx/libcx/handles.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Handle manipulation API. 3 | * Copyright (C) 2021 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2020. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef LIBCX_HANDLES_H 23 | #define LIBCX_HANDLES_H 24 | 25 | #include 26 | 27 | __BEGIN_DECLS 28 | 29 | #define LIBCX_HANDLE_SHMEM 1 30 | #define LIBCX_HANDLE_FD 2 31 | 32 | #define LIBCX_HANDLE_NEW 0x1 33 | 34 | #define LIBCX_HANDLE_CLOSE 0x1 35 | 36 | #pragma pack(1) 37 | typedef struct 38 | { 39 | union 40 | { 41 | int8_t type; /* LIBCX_HANDLE_SHMEM | LIBCX_HANDLE_FD */ 42 | int16_t _reserved1; 43 | }; 44 | int16_t flags; 45 | int32_t value; 46 | } LIBCX_HANDLE; 47 | #pragma pack() 48 | 49 | /** 50 | * Sends selected kLIBC and LIBCx handles to another LIBCx process. 51 | * 52 | * Once this function returns a success, the specified handles will be available 53 | * in the target process as if they were opened there directly or inherited from 54 | * a parent. If LIBCX_HANDLE_CLOSE is passed in `flags`, the handles will also 55 | * be closed in the calling (source) process on success. 56 | * 57 | * All handles in the array must be valid and belong to the source process. The 58 | * send operation is synchronous and "atomic" which means that it will either 59 | * successfully transfer all handles and return a success or transfer none and 60 | * return a failure. 61 | * 62 | * The purpose of this function is to share access to resources between two 63 | * existing processes. This is done by first calling this function and then 64 | * communicating the handles to the target process for their actual usage via 65 | * some sort of IPC. This function is useful if a PID of the target process is 66 | * known when handles are to be transferred. For other use cases, check 67 | * `libcx_take_handles`. 68 | * 69 | * Note that if the target process already has an open handle of the respected 70 | * type, this function will try to assign a different handle to the same 71 | * resource the source handle is associated with, as if it were duplicated. In 72 | * this case, the new handle will be passed to the caller at the same index of 73 | * the handles array and the `flags` field at this index will have 74 | * LIBCX_HANDLE_NEW flag set. The return value in this case will indicate a 75 | * number of new handles in the array. 76 | * 77 | * @param handles Array of handles to send. 78 | * @param[in] num_handles Number of entries in handles array. 79 | * @param[in] pid Target process ID. 80 | * @param[in] flags 0 or LIBCX_HANDLE_CLOSE. 81 | * 82 | * @return 0 or number of new handles on success, otherwise -1 and error 83 | * code in `errno`. 84 | */ 85 | int libcx_send_handles(LIBCX_HANDLE *handles, size_t num_handles, pid_t pid, int flags); 86 | 87 | /** 88 | * Takes selected kLIBC and LIBCx handles from another LIBCx process. 89 | * 90 | * Once this function returns a success, the specified handles will be made 91 | * accessible in the calling process as if they were opened there directly or 92 | * inherited from a parent. If LIBCX_HANDLE_CLOSE is passed in `flags`, the 93 | * handles will also be closed in another (source) process on success. 94 | * 95 | * All handles in the array must be valid and belong to the source process. The 96 | * take operation is synchronous and "atomic" which means that it will either 97 | * successfully transfers all handles and return a success or transfer none and 98 | * return a failure. 99 | * 100 | * The purpose of this function is to share access to resources between two 101 | * existing processes. This is done by first communicating the handles from the 102 | * source process to the target (calling) process and then calling this function 103 | * for their actual usage. This function is useful when a PID of the target 104 | * process is not known when the handles are to be transferred to it by the 105 | * source prcoess but a PID of the source process is known when they are 106 | * received in the target process via IPC. 107 | * 108 | * Note that if the target (calling) process already has an open handle of the 109 | * respected type, this function will try to assign a different handle to the 110 | * same resource the source handle is associated with, as if it were duplicated. 111 | * In this case, the new handle will be passed to the caller at the same index 112 | * of the handles array and the `flags` field at this index will have 113 | * LIBCX_HANDLE_NEW flag set. The return value in this case will indicate a 114 | * number of new handles in the array. 115 | * 116 | * @param handles Array of handles to take. 117 | * @param[in] num_handles Number of entries in handles array. 118 | * @param[in] pid Source process ID. 119 | * @param[in] flags 0 or LIBCX_HANDLE_CLOSE. 120 | * 121 | * @return 0 or number of new handles on success, otherwise -1 and error 122 | * code in `errno`. 123 | */ 124 | int libcx_take_handles(LIBCX_HANDLE *handles, size_t num_handles, pid_t pid, int flags); 125 | 126 | __END_DECLS 127 | 128 | #endif /* LIBCX_HANDLES_H */ 129 | -------------------------------------------------------------------------------- /src/main.s: -------------------------------------------------------------------------------- 1 | /* 2 | * main() hook implementation for kLIBC. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | /* 23 | * Designed after kLIBC sys/i386/appinit.s and must be kept in sync with it 24 | * and with startup/i386/crt0.s. Also depends on a LIBC import in libcx.def 25 | * (_libc___init_app). 26 | */ 27 | 28 | .globl ___init_app 29 | .globl ___main_hook_return 30 | 31 | .data 32 | 33 | L_ret: .long 0 34 | 35 | .text 36 | 37 | ___init_app: 38 | popl L_ret 39 | /* do original kLIBC work */ 40 | call __libc__init_app 41 | /* esp points to main() call frame. */ 42 | push %esp 43 | call ___main_hook 44 | /* Theoretically we never should get here. Force a SIGSEGV. */ 45 | hlt 46 | 47 | ___main_hook_return: 48 | movl 4(%esp), %esp 49 | jmp *L_ret 50 | -------------------------------------------------------------------------------- /src/mmap/mmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mmap implementation for kLIBC. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef MMAP_H 23 | #define MMAP_H 24 | 25 | #include 26 | 27 | #include "../shared.h" 28 | 29 | /* Width of a dirty map entry in bits */ 30 | #define DIRTYMAP_WIDTH (sizeof(*((struct FileDesc*)0)->fh->dirtymap) * 8) 31 | 32 | /* Flush operation start delay (ms) */ 33 | #define FLUSH_DELAY 1000 34 | 35 | /** 36 | * Per-process data for memory mappings. 37 | */ 38 | typedef struct ProcMemMap 39 | { 40 | int flush_tid; /* Flush thread */ 41 | HEV flush_sem; /* Semaphore for flush thread */ 42 | int flush_request; /* 1 - semaphore is posted */ 43 | } ProcMemMap; 44 | 45 | /** 46 | * File map's memory object (linked list entry). 47 | */ 48 | typedef struct FileMapMem 49 | { 50 | struct FileMapMem *next; 51 | 52 | struct FileMap *map; /* parent file map */ 53 | ULONG start; /* start address */ 54 | off_t off; /* offset from the beginning of the file */ 55 | ULONG len; /* object length */ 56 | int refcnt; /* number of MemMap entries using it */ 57 | } FileMapMem; 58 | 59 | /** 60 | * File map data. 61 | */ 62 | typedef struct FileMap 63 | { 64 | // FileDesc *desc; /* associated file desc */ 65 | int flags; /* Currently, MAP_SHARED or MAP_PRIVATE or 0 if not associated */ 66 | union 67 | { 68 | SharedFileDesc *desc_g; /* associated file desc for MAP_SHARED */ 69 | FileDesc *desc; /* associated file desc for MAP_PRIVATE */ 70 | }; 71 | FileMapMem *mems; /* list of memory objects of this file */ 72 | off_t size; /* file size */ 73 | } FileMap; 74 | 75 | /** 76 | * Process specific file handle. 77 | */ 78 | typedef struct FileHandle 79 | { 80 | FileDesc *desc; /* associated file desc */ 81 | HFILE fd; /* file handle (descriptor in LIBC) or -1 for MAP_ANONYMOUS */ 82 | size_t dirtymap_sz; /* size of dirty array in bytes */ 83 | uint32_t *dirtymap; /* bit array of dirty pages */ 84 | int refcnt; /* number of MemMap entries using it */ 85 | } FileHandle; 86 | 87 | /** 88 | * Memory mapping (linked list entry). 89 | */ 90 | typedef struct MemMap 91 | { 92 | struct MemMap *next; 93 | 94 | ULONG start; /* start address */ 95 | ULONG end; /* end address (exclusive) */ 96 | int flags; /* mmap flags */ 97 | ULONG dos_flags; /* DosAllocMem protection flags */ 98 | struct File /* Only present for non MAP_ANONYMOUS mmaps (must be last) */ 99 | { 100 | FileMapMem *fmem; /* file map's memory */ 101 | FileHandle *fh; /* File handle */ 102 | int refcnt; /* number of times this MemMap was returned by mmap */ 103 | } f[0]; 104 | } MemMap; 105 | 106 | #ifdef DEBUG 107 | void set_mmap_full_size(int val); 108 | MemMap *get_proc_mmaps(int pid); 109 | #endif 110 | 111 | #endif // MMAP_H 112 | -------------------------------------------------------------------------------- /src/mmap/sys/mman.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * FreeBSD 5.2 3 | * @changed bird: disabled most of the stuff we don't implement yet. 4 | */ 5 | /*- 6 | * Copyright (c) 1982, 1986, 1993 7 | * The Regents of the University of California. All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | * 33 | * @(#)mman.h 8.2 (Berkeley) 1/9/95 34 | * $FreeBSD: src/sys/sys/mman.h,v 1.39 2004/04/27 13:13:20 mux Exp $ 35 | */ 36 | 37 | #ifndef _SYS_MMAN_H_ 38 | #define _SYS_MMAN_H_ 39 | 40 | #include 41 | #include 42 | 43 | #if 0 /* bird */ 44 | #if __BSD_VISIBLE 45 | /* 46 | * Inheritance for minherit() 47 | */ 48 | #define INHERIT_SHARE 0 49 | #define INHERIT_COPY 1 50 | #define INHERIT_NONE 2 51 | #endif 52 | #endif /* bird */ 53 | 54 | /* 55 | * Protections are chosen from these bits, or-ed together 56 | */ 57 | #define PROT_NONE 0x00 /* no permissions */ 58 | #define PROT_READ 0x01 /* pages can be read */ 59 | #define PROT_WRITE 0x02 /* pages can be written */ 60 | #define PROT_EXEC 0x04 /* pages can be executed */ 61 | 62 | /* 63 | * Flags contain sharing type and options. 64 | * Sharing types; choose one. 65 | */ 66 | #define MAP_SHARED 0x0001 /* share changes */ 67 | #define MAP_PRIVATE 0x0002 /* changes are private */ 68 | #define MAP_COPY MAP_PRIVATE /* Obsolete */ 69 | 70 | #if __BSD_VISIBLE 71 | /* 72 | * Other flags 73 | */ 74 | #define MAP_FIXED 0x0010 /* map addr must be exactly as requested */ 75 | #define MAP_RENAME 0x0020 /* Sun: rename private pages to file */ 76 | #define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */ 77 | #define MAP_RESERVED0080 0x0080 /* previously misimplemented MAP_INHERIT */ 78 | #define MAP_RESERVED0100 0x0100 /* previously unimplemented MAP_NOEXTEND */ 79 | #define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */ 80 | #define MAP_STACK 0x0400 /* region grows down, like a stack */ 81 | #define MAP_NOSYNC 0x0800 /* page to but do not sync underlying file */ 82 | 83 | /* 84 | * Mapping type 85 | */ 86 | #define MAP_FILE 0x0000 /* map from file (default) */ 87 | #define MAP_ANONYMOUS 0x1000 /* allocated from memory, swap space */ 88 | #define MAP_ANON MAP_ANONYMOUS /* alias for MAP_ANONYMOUS, deprecated */ 89 | /* 90 | * Extended flags 91 | */ 92 | #define MAP_NOCORE 0x00020000 /* dont include these pages in a coredump */ 93 | #endif /* __BSD_VISIBLE */ 94 | 95 | #if __POSIX_VISIBLE >= 199309 96 | /* 97 | * Process memory locking 98 | */ 99 | #define MCL_CURRENT 0x0001 /* Lock only current memory */ 100 | #define MCL_FUTURE 0x0002 /* Lock all future memory as well */ 101 | #endif 102 | 103 | /* 104 | * Error return from mmap() 105 | */ 106 | #define MAP_FAILED ((void *)-1) 107 | 108 | /* 109 | * msync() flags 110 | */ 111 | #define MS_SYNC 0x0000 /* msync synchronously */ 112 | #define MS_ASYNC 0x0001 /* return immediately */ 113 | #define MS_INVALIDATE 0x0002 /* invalidate all cached data */ 114 | 115 | #if __BSD_VISIBLE 116 | /* 117 | * Advice to madvise 118 | */ 119 | #define MADV_NORMAL 0 /* no further special treatment */ 120 | #define MADV_RANDOM 1 /* expect random page references */ 121 | #define MADV_SEQUENTIAL 2 /* expect sequential page references */ 122 | #define MADV_WILLNEED 3 /* will need these pages */ 123 | #define MADV_DONTNEED 4 /* dont need these pages */ 124 | #define MADV_FREE 5 /* dont need these pages, and junk contents */ 125 | #define MADV_NOSYNC 6 /* try to avoid flushes to physical media */ 126 | #define MADV_AUTOSYNC 7 /* revert to default flushing strategy */ 127 | #define MADV_NOCORE 8 /* do not include these pages in a core file */ 128 | #define MADV_CORE 9 /* revert to including pages in a core file */ 129 | #define MADV_PROTECT 10 /* protect process from pageout kill */ 130 | 131 | /* 132 | * Return bits from mincore 133 | */ 134 | #define MINCORE_INCORE 0x1 /* Page is incore */ 135 | #define MINCORE_REFERENCED 0x2 /* Page has been referenced by us */ 136 | #define MINCORE_MODIFIED 0x4 /* Page has been modified by us */ 137 | #define MINCORE_REFERENCED_OTHER 0x8 /* Page has been referenced */ 138 | #define MINCORE_MODIFIED_OTHER 0x10 /* Page has been modified */ 139 | #endif /* __BSD_VISIBLE */ 140 | 141 | /* 142 | * XXX missing POSIX_TYPED_MEM_* macros and 143 | * posix_typed_mem_info structure. 144 | */ 145 | #if __POSIX_VISIBLE >= 200112 146 | #define POSIX_MADV_NORMAL MADV_NORMAL 147 | #define POSIX_MADV_RANDOM MADV_RANDOM 148 | #define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL 149 | #define POSIX_MADV_WILLNEED MADV_WILLNEED 150 | #define POSIX_MADV_DONTNEED MADV_DONTNEED 151 | #endif 152 | 153 | #ifndef _MODE_T_DECLARED 154 | typedef __mode_t mode_t; 155 | #define _MODE_T_DECLARED 156 | #endif 157 | 158 | #ifndef _OFF_T_DECLARED 159 | typedef __off_t off_t; 160 | #define _OFF_T_DECLARED 161 | #endif 162 | 163 | #ifndef _SIZE_T_DECLARED 164 | typedef __size_t size_t; 165 | #define _SIZE_T_DECLARED 166 | #endif 167 | 168 | #ifndef _KERNEL 169 | 170 | __BEGIN_DECLS 171 | /* 172 | * XXX not yet implemented: posix_mem_offset(), posix_typed_mem_get_info(), 173 | * posix_typed_mem_open(). 174 | */ 175 | #if __BSD_VISIBLE 176 | int madvise(void *, size_t, int); 177 | /** @todo int mincore(const void *, size_t, char *); */ 178 | /** @todo int minherit(void *, size_t, int); */ 179 | #endif 180 | /** @todo int mlock(const void *, size_t); */ 181 | #ifndef _MMAP_DECLARED 182 | #define _MMAP_DECLARED 183 | void * mmap(void *, size_t, int, int, int, off_t); 184 | #endif 185 | int mprotect(const void *, size_t, int); 186 | int msync(void *, size_t, int); 187 | /** @todo int munlock(const void *, size_t); */ 188 | int munmap(void *, size_t); 189 | #if __POSIX_VISIBLE >= 200112 190 | int posix_madvise(void *, size_t, int); 191 | #endif 192 | #if __POSIX_VISIBLE >= 199309 193 | /** @todo int mlockall(int); */ 194 | /** @todo int munlockall(void); */ 195 | /** @todo int shm_open(const char *, int, mode_t); */ 196 | /** @todo int shm_unlink(const char *); */ 197 | #endif 198 | __END_DECLS 199 | 200 | #endif /* !_KERNEL */ 201 | 202 | #endif /* !_SYS_MMAN_H_ */ 203 | -------------------------------------------------------------------------------- /src/mmap/tst-anon_mmap2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for anonymous private mmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #define _BSD_SOURCE /* Get MAP_ANONYMOUS definition */ 23 | #include 24 | #include 25 | #include 26 | 27 | static int do_test(void); 28 | #define TEST_FUNCTION do_test() 29 | #include "../test-skeleton.c" 30 | 31 | #ifndef PAGE_SIZE 32 | #define PAGE_SIZE 4096 33 | #endif 34 | #define MEM_SIZE (PAGE_SIZE * 10) 35 | 36 | static int do_test(void) 37 | { 38 | int status; 39 | char *mem; 40 | 41 | mem = (char *)mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, 42 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 43 | if (mem == MAP_FAILED) 44 | { 45 | perror ("mmap failed"); 46 | exit(-1); 47 | } 48 | 49 | if (*mem != 0) 50 | { 51 | printf("value is %d, must be 0\n", *mem); 52 | exit(-1); 53 | } 54 | 55 | *mem = 1; 56 | 57 | if (*mem != 1) 58 | { 59 | printf("value is %d, must be 1\n", *mem); 60 | exit(-1); 61 | } 62 | 63 | mem[PAGE_SIZE * 2] = 2; 64 | if (mem[PAGE_SIZE * 2] != 2) 65 | { 66 | printf("value is %d, must be 2\n", mem[PAGE_SIZE * 2]); 67 | exit(-1); 68 | } 69 | 70 | if (munmap(mem, MEM_SIZE) == -1) 71 | { 72 | perror ("munmap failed"); 73 | exit(-1); 74 | } 75 | 76 | switch (fork()) 77 | { 78 | case -1: 79 | perror("fork failed"); 80 | exit(-1); 81 | case 0: 82 | mem = (char *)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, 83 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 84 | if (mem == MAP_FAILED) 85 | { 86 | perror ("mmap failed"); 87 | exit(-1); 88 | } 89 | 90 | if (*mem != 0) 91 | { 92 | printf("value is %d, must be 0\n", *mem); 93 | exit(-1); 94 | } 95 | 96 | *mem = 1; 97 | 98 | if (*mem != 1) 99 | { 100 | printf("value is %d, must be 1\n", *mem); 101 | exit(-1); 102 | } 103 | 104 | /* This should crash the child with SIGSEGV */ 105 | mem[PAGE_SIZE] = 2; 106 | exit(EXIT_SUCCESS); 107 | } 108 | 109 | if (wait(&status) == -1) 110 | { 111 | perror("wait failed"); 112 | exit(-1); 113 | } 114 | if (WIFEXITED(status) || !WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) 115 | { 116 | printf("child ended sucessfully or crashed not with SIGSEGV (status %x)\n", status); 117 | exit(-1); 118 | } 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /src/mmap/tst-madvise.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for madvise. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifdef __OS2__ 28 | #include 29 | #endif 30 | #include 31 | #include 32 | 33 | #ifndef PAGE_SIZE 34 | #define PAGE_SIZE 4096 35 | #endif 36 | 37 | #define FILE_SIZE (PAGE_SIZE * 3) 38 | #define FILE_VAL 1 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | /* Shared mapping file flush interval in ms (must match one from mmap.c) */ 43 | #define FLUSH_DELAY 1000 44 | 45 | unsigned char buf[FILE_SIZE]; 46 | unsigned char buf_chk[FILE_SIZE]; 47 | unsigned char buf2[TEST_SIZE * 2]; 48 | 49 | static int do_test(void); 50 | #define TEST_FUNCTION do_test () 51 | #include "../test-skeleton.c" 52 | 53 | static int 54 | do_test (void) 55 | { 56 | int rc; 57 | int i, n; 58 | unsigned char *addr; 59 | char *fname; 60 | int status; 61 | 62 | int fd = create_temp_file("tst-madvise-", &fname); 63 | if (fd == -1) 64 | { 65 | puts("create_temp_file failed"); 66 | return 1; 67 | } 68 | 69 | #ifdef __OS2__ 70 | setmode(fd, O_BINARY); 71 | #endif 72 | 73 | for (i = 0; i < FILE_SIZE; ++i) 74 | buf[i] = FILE_VAL; 75 | 76 | if ((n = write(fd, buf, FILE_SIZE)) != FILE_SIZE) 77 | { 78 | if (n != -1) 79 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 80 | else 81 | perror("write failed"); 82 | return 1; 83 | } 84 | 85 | // This is not supported for now, see README.md. 86 | #if 0 87 | /* 88 | * Test 1: create shared mmap, modify underlying file, MADV_DONTNEED a page 89 | * then read it to check that it gets new file contents. 90 | */ 91 | 92 | printf("Test 1\n"); 93 | 94 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 95 | if (addr == MAP_FAILED) 96 | { 97 | perror("mmap failed"); 98 | exit(-1); 99 | } 100 | 101 | for (i = 0; i < FILE_SIZE; ++i) 102 | { 103 | if (addr[i] != buf[i]) 104 | { 105 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 106 | return 1; 107 | } 108 | } 109 | 110 | for (i = 0; i < PAGE_SIZE; ++i) 111 | buf[i] = TEST_VAL; 112 | 113 | if (lseek(fd, PAGE_SIZE, SEEK_SET) == -1) 114 | { 115 | perror("lseek failed"); 116 | return 1; 117 | } 118 | 119 | if ((n = write(fd, buf, PAGE_SIZE)) != PAGE_SIZE) 120 | { 121 | if (n != -1) 122 | printf("write failed (write %d bytes instead of %d)\n", n, PAGE_SIZE); 123 | else 124 | perror("write failed"); 125 | return 1; 126 | } 127 | 128 | rc = madvise(addr + PAGE_SIZE, PAGE_SIZE, MADV_DONTNEED); 129 | if (rc == -1) 130 | { 131 | perror("madvise failed"); 132 | return 1; 133 | } 134 | 135 | for (i = PAGE_SIZE; i < PAGE_SIZE * 2; ++i) 136 | { 137 | if (addr[i] != TEST_VAL) 138 | { 139 | printf("addr[%d] is %u, must be %u\n", i, addr[i], TEST_VAL); 140 | return 1; 141 | } 142 | } 143 | 144 | if (munmap(addr, FILE_SIZE) == -1) 145 | { 146 | perror("munmap failed"); 147 | return 1; 148 | } 149 | 150 | #endif 151 | 152 | /* 153 | * Test 2: create private mmap, modify underlying file, MADV_DONTNEED a page 154 | * then read it to check that it gets new file contents. 155 | */ 156 | 157 | printf("Test 2\n"); 158 | 159 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 160 | if (addr == MAP_FAILED) 161 | { 162 | perror("mmap failed"); 163 | exit(-1); 164 | } 165 | 166 | for (i = 0; i < FILE_SIZE; ++i) 167 | { 168 | if (addr[i] != buf[i]) 169 | { 170 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 171 | return 1; 172 | } 173 | } 174 | 175 | for (i = 0; i < PAGE_SIZE; ++i) 176 | buf[i] = TEST_VAL; 177 | 178 | if (lseek(fd, PAGE_SIZE, SEEK_SET) == -1) 179 | { 180 | perror("lseek failed"); 181 | return 1; 182 | } 183 | 184 | if ((n = write(fd, buf, PAGE_SIZE)) != PAGE_SIZE) 185 | { 186 | if (n != -1) 187 | printf("write failed (write %d bytes instead of %d)\n", n, PAGE_SIZE); 188 | else 189 | perror("write failed"); 190 | return 1; 191 | } 192 | 193 | rc = madvise(addr + PAGE_SIZE, PAGE_SIZE, MADV_DONTNEED); 194 | if (rc == -1) 195 | { 196 | perror("madvise failed"); 197 | return 1; 198 | } 199 | 200 | for (i = PAGE_SIZE; i < PAGE_SIZE * 2; ++i) 201 | { 202 | if (addr[i] != TEST_VAL) 203 | { 204 | printf("addr[%d] is %u, must be %u\n", i, addr[i], TEST_VAL); 205 | return 1; 206 | } 207 | } 208 | 209 | if (munmap(addr, FILE_SIZE) == -1) 210 | { 211 | perror("munmap failed"); 212 | return 1; 213 | } 214 | 215 | /* 216 | * Test 3: create private anonymous mapping, change somebytes, then DONTNEED 217 | * it, should read 0 218 | */ 219 | 220 | printf("Test 3\n"); 221 | 222 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 223 | if (addr == MAP_FAILED) 224 | { 225 | perror("mmap failed"); 226 | exit(-1); 227 | } 228 | 229 | for (i = 0; i < FILE_SIZE; ++i) 230 | addr[i] = buf[i]; 231 | 232 | rc = madvise(addr + PAGE_SIZE, PAGE_SIZE * 10, MADV_DONTNEED); 233 | if (rc == -1) 234 | { 235 | perror("madvise failed"); 236 | return 1; 237 | } 238 | 239 | for (i = 0; i < PAGE_SIZE; ++i) 240 | { 241 | if (addr[i] != buf[i]) 242 | { 243 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 244 | return 1; 245 | } 246 | } 247 | 248 | for (i = PAGE_SIZE; i < FILE_SIZE; ++i) 249 | { 250 | if (addr[i] != 0) 251 | { 252 | printf("addr[%d] is %u, must be %u\n", i, addr[i], 0); 253 | return 1; 254 | } 255 | } 256 | 257 | if (munmap(addr, FILE_SIZE) == -1) 258 | { 259 | perror("munmap failed"); 260 | return 1; 261 | } 262 | 263 | return 0; 264 | } 265 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for shared mmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 4) 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | unsigned char buf[FILE_SIZE]; 43 | unsigned char buf2[TEST_SIZE * 2]; 44 | 45 | static int do_test(void); 46 | #define TEST_FUNCTION do_test () 47 | #include "../test-skeleton.c" 48 | 49 | static int 50 | do_test (void) 51 | { 52 | int rc; 53 | int i, n; 54 | unsigned char *addr, *addr2; 55 | char *fname; 56 | int status; 57 | 58 | int fd = create_temp_file("tst-mmap-", &fname); 59 | if (fd == -1) 60 | { 61 | puts("create_temp_file failed"); 62 | return 1; 63 | } 64 | 65 | #ifdef __OS2__ 66 | setmode (fd, O_BINARY); 67 | #endif 68 | 69 | srand(getpid()); 70 | 71 | for (i = 0; i < FILE_SIZE; ++i) 72 | buf[i] = rand() % 255; 73 | 74 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 75 | { 76 | if (n != -1) 77 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 78 | else 79 | perror("write failed"); 80 | return 1; 81 | } 82 | 83 | /* 84 | * Test 1: simple mmap 85 | */ 86 | 87 | printf("Test 1\n"); 88 | 89 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 90 | if (addr == MAP_FAILED) 91 | { 92 | perror("mmap failed"); 93 | exit(-1); 94 | } 95 | 96 | addr2 = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 97 | if (addr2 == MAP_FAILED) 98 | { 99 | perror("mmap 2 failed"); 100 | exit(-1); 101 | } 102 | 103 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 104 | { 105 | if (addr[i] != buf[i]) 106 | { 107 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 108 | return 1; 109 | } 110 | } 111 | 112 | if (munmap(addr, FILE_SIZE) == -1) 113 | { 114 | perror("munmap failed"); 115 | return 1; 116 | } 117 | 118 | if (munmap(addr2, FILE_SIZE) == -1) 119 | { 120 | perror("munmap 2 failed"); 121 | return 1; 122 | } 123 | 124 | /* 125 | * Test 2: mmap at offset 126 | */ 127 | 128 | printf("Test 2\n"); 129 | 130 | enum { Offset = PAGE_SIZE }; 131 | 132 | addr = mmap(NULL, FILE_SIZE - Offset, PROT_READ | PROT_WRITE, MAP_SHARED, fd, Offset); 133 | if (addr == MAP_FAILED) 134 | { 135 | perror("mmap failed"); 136 | exit(-1); 137 | } 138 | 139 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 140 | { 141 | if (addr[i] != buf[i + Offset]) 142 | { 143 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i + Offset]); 144 | return 1; 145 | } 146 | } 147 | 148 | /* 149 | * Test 3: modify mmap (should change the underlying file and be visible 150 | * in children) 151 | */ 152 | 153 | printf("Test 3\n"); 154 | 155 | switch (fork()) 156 | { 157 | case -1: 158 | perror("fork failed"); 159 | exit(-1); 160 | 161 | case 0: 162 | 163 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 164 | { 165 | if (addr[i] != buf[i + Offset]) 166 | { 167 | printf("child: addr[%d] is %u, must be %u\n", i, addr[i], buf[i + Offset]); 168 | return 1; 169 | } 170 | } 171 | 172 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 173 | addr[i] = TEST_VAL; 174 | 175 | if (munmap(addr, FILE_SIZE - Offset) == -1) 176 | { 177 | perror("child: munmap failed"); 178 | return 1; 179 | } 180 | 181 | forget_temp_file (fname, fd); 182 | 183 | return 0; 184 | } 185 | 186 | if (wait(&status) == -1) 187 | { 188 | perror("wait failed"); 189 | return 1; 190 | } 191 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 192 | { 193 | printf("child crashed or returned non-zero (status %x)\n", status); 194 | return 1; 195 | } 196 | 197 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 198 | { 199 | if (addr[i] != TEST_VAL) 200 | printf("addr[%d] is %u, must be %u\n", i, addr[i], TEST_VAL); 201 | } 202 | 203 | if (munmap(addr, FILE_SIZE - Offset) == -1) 204 | { 205 | perror("munmap failed"); 206 | return 1; 207 | } 208 | 209 | close(fd); 210 | 211 | fd = open(fname, O_RDONLY); 212 | if (fd == -1) 213 | { 214 | perror("open failed"); 215 | return 1; 216 | } 217 | 218 | if (lseek(fd, Offset + PAGE_SIZE - TEST_SIZE, SEEK_SET) == -1) 219 | { 220 | perror("lseek failed"); 221 | return 1; 222 | } 223 | 224 | if (TEMP_FAILURE_RETRY((n = read(fd, buf2, TEST_SIZE * 2))) != TEST_SIZE * 2) 225 | { 226 | if (n != -1) 227 | printf("read failed (read %d bytes instead of %d)\n", n, TEST_SIZE * 2); 228 | else 229 | perror("read failed"); 230 | return 1; 231 | } 232 | 233 | for (i = 0; i < TEST_SIZE * 2; ++i) 234 | { 235 | if (buf2[i] != TEST_VAL) 236 | { 237 | printf("buf2[%d] is %u, must be %u\n", i, buf2[i], TEST_VAL); 238 | return 1; 239 | } 240 | } 241 | 242 | close(fd); 243 | 244 | free(fname); 245 | 246 | return 0; 247 | } 248 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap10.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for big mmap allocation. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifndef PAGE_SIZE 31 | #define PAGE_SIZE 4096 32 | #endif 33 | 34 | #define WIN_SIZE (1024U * 1024U * 32U) // 32M 35 | 36 | static int do_test(void); 37 | #define TEST_FUNCTION do_test () 38 | #include "../test-skeleton.c" 39 | 40 | static int 41 | do_test (void) 42 | { 43 | int rc; 44 | int i, n; 45 | unsigned char **addr; 46 | unsigned int max_size; 47 | off_t off; 48 | char *fname; 49 | 50 | int fd = create_temp_file("tst-mmap10-", &fname); 51 | if (fd == -1) 52 | { 53 | perror("create_temp_file failed"); 54 | return 1; 55 | } 56 | 57 | max_size = (1024U * 1024U * 1024U); // 1G 58 | addr = (unsigned char **)malloc(max_size / WIN_SIZE * sizeof(*addr)); 59 | 60 | printf("Test 1: %i iterations (up to 0x%x bytes)\n", max_size / WIN_SIZE, max_size); 61 | 62 | for (i = 0, off = 0; i < max_size / WIN_SIZE; ++i, off += WIN_SIZE) 63 | { 64 | printf("Iteration %d, off 0x%llx, len 0x%x\n", i, off, WIN_SIZE); 65 | 66 | addr[i] = mmap(NULL, WIN_SIZE, PROT_READ, MAP_PRIVATE, fd, off); 67 | if (addr[i] == MAP_FAILED) 68 | { 69 | perror("mmap failed"); 70 | return 1; 71 | } 72 | } 73 | 74 | for (i = 0; i < max_size / WIN_SIZE; ++i) 75 | { 76 | if (munmap(addr[i], WIN_SIZE) == -1) 77 | { 78 | perror("munmap failed"); 79 | return 1; 80 | } 81 | } 82 | 83 | free(addr); 84 | free(fname); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap11.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for multi-threaded and multi-process concurrent mmap access. 3 | * Copyright (C) 2019 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2019. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define INCL_BASE 32 | #include 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 300) 39 | 40 | unsigned char buf[FILE_SIZE]; 41 | 42 | static int do_test(void); 43 | #define TEST_FUNCTION do_test () 44 | #include "../test-skeleton.c" 45 | 46 | void thread_func(void *arg) 47 | { 48 | unsigned char *addr = arg; 49 | 50 | int i; 51 | 52 | /* 53 | * Test 1: simple mmap 54 | */ 55 | 56 | printf("pid %d tid %d: Test 1\n", getpid(), _gettid()); 57 | 58 | for (i = 0; i < FILE_SIZE; ++i) 59 | { 60 | if (addr[i] != buf[i]) 61 | { 62 | printf("tid %d: addr[%d] is %u, must be %u\n", _gettid(), i, addr[i], buf[i]); 63 | exit(-1); 64 | } 65 | } 66 | 67 | printf("pid %d tid %d: Test END\n", getpid(), _gettid()); 68 | } 69 | 70 | 71 | static int 72 | do_test (void) 73 | { 74 | int rc; 75 | int i, n; 76 | unsigned char *addr; 77 | char *fname; 78 | 79 | int fd = create_temp_file("tst-mmap11-", &fname); 80 | if (fd == -1) 81 | { 82 | puts("create_temp_file failed"); 83 | return 1; 84 | } 85 | 86 | #ifdef __OS2__ 87 | setmode (fd, O_BINARY); 88 | #endif 89 | 90 | srand(getpid()); 91 | 92 | for (i = 0; i < FILE_SIZE; ++i) 93 | buf[i] = rand() % 255; 94 | 95 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 96 | { 97 | if (n != -1) 98 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 99 | else 100 | perrno("write failed"); 101 | return 1; 102 | } 103 | 104 | /* 105 | * Test 1: threads 106 | */ 107 | 108 | printf("Test 1\n"); 109 | 110 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 111 | if (addr == MAP_FAILED) 112 | { 113 | perror("mmap failed"); 114 | exit(-1); 115 | } 116 | 117 | #if DEBUG 118 | // May be slow due to logging so limit the number of threads 119 | int tids[5] = {0}; 120 | #else 121 | int tids[50] = {0}; 122 | #endif 123 | 124 | for (i = 0; i < sizeof(tids)/sizeof(tids[0]); ++i) 125 | { 126 | tids[i] = _beginthread (thread_func, NULL, 0, addr); 127 | if (tids[i] == -1) 128 | { 129 | perrno("_beginthread"); 130 | return 1; 131 | } 132 | } 133 | 134 | for (i = 0; i < sizeof(tids)/sizeof(tids[0]); ++i) 135 | { 136 | APIRET arc = DosWaitThread((PTID)&tids[i], DCWW_WAIT); 137 | if (arc && arc != ERROR_INVALID_THREADID) 138 | { 139 | perr("DosWaitThread returned %ld", arc); 140 | return 1; 141 | } 142 | } 143 | 144 | if (munmap(addr, FILE_SIZE) == -1) 145 | { 146 | perrno("munmap failed"); 147 | return 1; 148 | } 149 | 150 | close(fd); 151 | 152 | /* 153 | * Test 2: processes 154 | */ 155 | 156 | printf("Test 2\n"); 157 | 158 | fd = open(fname, O_RDONLY); 159 | if (fd == -1) 160 | { 161 | perror("open failed"); 162 | return 1; 163 | } 164 | 165 | addr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_SHARED, fd, 0); 166 | if (addr == MAP_FAILED) 167 | { 168 | perror("mmap failed"); 169 | exit(-1); 170 | } 171 | 172 | int pids[7] = {0}; 173 | 174 | for (i = 0; i < sizeof(pids)/sizeof(pids[0]); ++i) 175 | { 176 | int pid; 177 | 178 | switch ((pid = fork())) 179 | { 180 | case -1: 181 | perror("fork failed"); 182 | exit(-1); 183 | 184 | case 0: 185 | { 186 | /* Child */ 187 | 188 | thread_func(addr); 189 | 190 | return 0; 191 | } 192 | 193 | default: 194 | pids[i] = pid; 195 | } 196 | } 197 | 198 | rc = 0; 199 | 200 | for (i = 0; i < sizeof(pids)/sizeof(pids[0]); ++i) 201 | { 202 | int status; 203 | 204 | if (waitpid(pids[i], &status, 0) == -1) 205 | { 206 | perror("waitpid failed"); 207 | rc = -1; 208 | } 209 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 210 | { 211 | printf("child crashed or returned non-zero (status %x)\n", status); 212 | rc = -1; 213 | } 214 | } 215 | 216 | if (munmap(addr, FILE_SIZE) == -1) 217 | { 218 | perrno("munmap failed"); 219 | return -1; 220 | } 221 | 222 | close(fd); 223 | 224 | free(fname); 225 | 226 | return rc; 227 | } 228 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap12.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for memchr and mmap. 3 | * Copyright (C) 2019 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2019. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | static int do_test(void); 32 | #define TEST_FUNCTION do_test () 33 | #include "../test-skeleton.c" 34 | 35 | 36 | #if 0 37 | 38 | static int 39 | do_test (void) 40 | { 41 | } 42 | 43 | #else 44 | 45 | #define ASSERT assert 46 | #define HAVE_SYS_MMAN_H 1 47 | #define HAVE_MPROTECT 1 48 | #define HAVE_MAP_ANONYMOUS 1 49 | 50 | /* Return a pointer to a zero-size object in memory (that is, actually, a 51 | pointer to a page boundary where the previous page is readable and writable 52 | and the next page is neither readable not writable), if possible. 53 | Return NULL otherwise. */ 54 | 55 | static void * 56 | zerosize_ptr (void) 57 | { 58 | /* Use mmap and mprotect when they exist. Don't test HAVE_MMAP, because it is 59 | not defined on HP-UX 11 (since it does not support MAP_FIXED). */ 60 | #if HAVE_SYS_MMAN_H && HAVE_MPROTECT 61 | # if HAVE_MAP_ANONYMOUS 62 | const int flags = MAP_ANONYMOUS | MAP_PRIVATE; 63 | const int fd = -1; 64 | # else /* !HAVE_MAP_ANONYMOUS */ 65 | const int flags = MAP_FILE | MAP_PRIVATE; 66 | int fd = open ("/dev/zero", O_RDONLY, 0666); 67 | if (fd >= 0) 68 | # endif 69 | { 70 | int pagesize = getpagesize (); 71 | char *two_pages = 72 | (char *) mmap (NULL, 2 * pagesize, PROT_READ | PROT_WRITE, 73 | flags, fd, 0); 74 | if (two_pages != (char *)(-1) 75 | && mprotect (two_pages + pagesize, pagesize, PROT_NONE) == 0) 76 | // && munmap (two_pages + pagesize, pagesize) == 0) 77 | return two_pages + pagesize; 78 | } 79 | #endif 80 | return NULL; 81 | } 82 | 83 | /* Calculating void * + int is not portable, so this wrapper converts 84 | to char * to make the tests easier to write. */ 85 | #define MEMCHR (char *) memchr 86 | 87 | static int 88 | do_test (void) 89 | { 90 | size_t n = 0x100000; 91 | char *input = malloc (n); 92 | ASSERT (input); 93 | 94 | input[0] = 'a'; 95 | input[1] = 'b'; 96 | memset (input + 2, 'c', 1024); 97 | memset (input + 1026, 'd', n - 1028); 98 | input[n - 2] = 'e'; 99 | input[n - 1] = 'a'; 100 | 101 | /* Basic behavior tests. */ 102 | ASSERT (MEMCHR (input, 'a', n) == input); 103 | 104 | ASSERT (MEMCHR (input, 'a', 0) == NULL); 105 | printf ("Test 1\n"); 106 | ASSERT (MEMCHR (zerosize_ptr (), 'a', 0) == NULL); 107 | printf ("Test 2\n"); 108 | 109 | ASSERT (MEMCHR (input, 'b', n) == input + 1); 110 | ASSERT (MEMCHR (input, 'c', n) == input + 2); 111 | ASSERT (MEMCHR (input, 'd', n) == input + 1026); 112 | 113 | ASSERT (MEMCHR (input + 1, 'a', n - 1) == input + n - 1); 114 | ASSERT (MEMCHR (input + 1, 'e', n - 1) == input + n - 2); 115 | ASSERT (MEMCHR (input + 1, 0x789abc00 | 'e', n - 1) == input + n - 2); 116 | 117 | ASSERT (MEMCHR (input, 'f', n) == NULL); 118 | ASSERT (MEMCHR (input, '\0', n) == NULL); 119 | 120 | /* Check that a very long haystack is handled quickly if the byte is 121 | found near the beginning. */ 122 | { 123 | size_t repeat = 10000; 124 | for (; repeat > 0; repeat--) 125 | { 126 | ASSERT (MEMCHR (input, 'c', n) == input + 2); 127 | } 128 | } 129 | 130 | /* Alignment tests. */ 131 | { 132 | int i, j; 133 | for (i = 0; i < 32; i++) 134 | { 135 | for (j = 0; j < 256; j++) 136 | input[i + j] = j; 137 | for (j = 0; j < 256; j++) 138 | { 139 | ASSERT (MEMCHR (input + i, j, 256) == input + i + j); 140 | } 141 | } 142 | } 143 | 144 | printf ("Test 3.1\n"); 145 | 146 | /* Check that memchr() does not read past the first occurrence of the 147 | byte being searched. See the Austin Group's clarification 148 | . 149 | Test both '\0' and something else, since some implementations 150 | special-case searching for NUL. 151 | */ 152 | { 153 | char *page_boundary = (char *) zerosize_ptr (); 154 | /* Too small, and we miss cache line boundary tests; too large, 155 | and the test takes cubically longer to complete. */ 156 | int limit = 257; 157 | 158 | if (page_boundary != NULL) 159 | { 160 | for (n = 1; n <= limit; n++) 161 | { 162 | printf ("Test 3.2.1: %d\n", n); 163 | char *mem = page_boundary - n; 164 | printf ("Test 3.2.2\n"); 165 | memset (mem, 'X', n); 166 | printf ("Test 3.2.3\n"); 167 | ASSERT (MEMCHR (mem, 'U', n) == NULL); 168 | printf ("Test 3.2.4\n"); 169 | ASSERT (MEMCHR (mem, 0, n) == NULL); 170 | 171 | printf ("Test 3.2.5\n"); 172 | { 173 | size_t i; 174 | size_t k; 175 | 176 | for (i = 0; i < n; i++) 177 | { 178 | mem[i] = 'U'; 179 | for (k = i + 1; k < n + limit; k++) 180 | ASSERT (MEMCHR (mem, 'U', k) == mem + i); 181 | mem[i] = 0; 182 | for (k = i + 1; k < n + limit; k++) 183 | ASSERT (MEMCHR (mem, 0, k) == mem + i); 184 | mem[i] = 'X'; 185 | } 186 | } 187 | } 188 | } 189 | } 190 | 191 | free (input); 192 | 193 | return 0; 194 | } 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for private mmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 4) 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | unsigned char buf[FILE_SIZE]; 43 | unsigned char buf2[TEST_SIZE * 2]; 44 | 45 | static int do_test(void); 46 | #define TEST_FUNCTION do_test () 47 | #include "../test-skeleton.c" 48 | 49 | static int 50 | do_test (void) 51 | { 52 | int rc; 53 | int i, n; 54 | unsigned char *addr; 55 | char *fname; 56 | 57 | int fd = create_temp_file("tst-mmap2-", &fname); 58 | if (fd == -1) 59 | { 60 | puts("create_temp_file failed"); 61 | return 1; 62 | } 63 | 64 | #ifdef __OS2__ 65 | setmode (fd, O_BINARY); 66 | #endif 67 | 68 | srand(getpid()); 69 | 70 | for (i = 0; i < FILE_SIZE; ++i) 71 | buf[i] = rand() % 255; 72 | 73 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 74 | { 75 | if (n != -1) 76 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 77 | else 78 | perror("write failed"); 79 | return 1; 80 | } 81 | 82 | /* 83 | * Test 1: simple mmap 84 | */ 85 | 86 | printf("Test 1\n"); 87 | 88 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 89 | if (addr == MAP_FAILED) 90 | { 91 | perror("mmap failed"); 92 | exit(-1); 93 | } 94 | 95 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 96 | { 97 | if (addr[i] != buf[i]) 98 | { 99 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 100 | return 1; 101 | } 102 | } 103 | 104 | if (munmap(addr, FILE_SIZE) == -1) 105 | { 106 | perror("munmap failed"); 107 | return 1; 108 | } 109 | 110 | /* 111 | * Test 2: mmap at offset 112 | */ 113 | 114 | printf("Test 2\n"); 115 | 116 | enum { Offset = PAGE_SIZE }; 117 | 118 | addr = mmap(NULL, FILE_SIZE - Offset, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, Offset); 119 | if (addr == MAP_FAILED) 120 | { 121 | perror("mmap failed"); 122 | exit(-1); 123 | } 124 | 125 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 126 | { 127 | if (addr[i] != buf[i + Offset]) 128 | { 129 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i + Offset]); 130 | return 1; 131 | } 132 | } 133 | 134 | /* 135 | * Test 3: modify mmap (should not change the underlying file) 136 | */ 137 | 138 | printf("Test 3\n"); 139 | 140 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 141 | addr[i] = TEST_VAL; 142 | 143 | if (munmap(addr, FILE_SIZE - Offset) == -1) 144 | { 145 | perror("munmap failed"); 146 | return 1; 147 | } 148 | 149 | close(fd); 150 | 151 | fd = open(fname, O_RDONLY); 152 | if (fd == -1) 153 | { 154 | perror("open failed"); 155 | return 1; 156 | } 157 | 158 | #ifdef __OS2__ 159 | setmode (fd, O_BINARY); 160 | #endif 161 | 162 | if (lseek(fd, Offset + PAGE_SIZE - TEST_SIZE, SEEK_CUR) == -1) 163 | { 164 | perror("lseek failed"); 165 | return 1; 166 | } 167 | 168 | if (TEMP_FAILURE_RETRY((n = read(fd, buf2, TEST_SIZE * 2))) != TEST_SIZE * 2) 169 | { 170 | if (n != -1) 171 | printf("read failed (read %d bytes instead of %d)\n", n, TEST_SIZE * 2); 172 | else 173 | perror("read failed"); 174 | return 1; 175 | } 176 | 177 | for (i = 0; i < TEST_SIZE * 2; ++i) 178 | { 179 | if (buf2[i] != buf[i + Offset + PAGE_SIZE - TEST_SIZE]) 180 | { 181 | printf("buf2[%d] is %u, must be %u\n", i, buf2[i], buf[i + Offset]); 182 | return 1; 183 | } 184 | } 185 | 186 | close(fd); 187 | 188 | free(fname); 189 | 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for r/o mmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 2) 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | unsigned char buf[FILE_SIZE]; 43 | unsigned char buf2[TEST_SIZE * 2]; 44 | 45 | static int do_test(void); 46 | #define TEST_FUNCTION do_test () 47 | #include "../test-skeleton.c" 48 | 49 | static int 50 | do_test (void) 51 | { 52 | int rc; 53 | int i, n; 54 | unsigned char *addr; 55 | char *fname; 56 | 57 | int fd = create_temp_file("tst-mmap3-", &fname); 58 | if (fd == -1) 59 | { 60 | perror("create_temp_file failed"); 61 | return 1; 62 | } 63 | 64 | #ifdef __OS2__ 65 | setmode (fd, O_BINARY); 66 | #endif 67 | 68 | srand(getpid()); 69 | 70 | for (i = 0; i < FILE_SIZE; ++i) 71 | buf[i] = rand() % 255; 72 | 73 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 74 | { 75 | if (n != -1) 76 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 77 | else 78 | perror("write failed"); 79 | return 1; 80 | } 81 | 82 | int fd2 = open(fname, O_RDONLY); 83 | if (fd2 == -1) 84 | { 85 | perror("open failed"); 86 | return 1; 87 | } 88 | 89 | close(fd); 90 | 91 | /* 92 | * Test 1: simple mmap 93 | */ 94 | 95 | printf("Test 1\n"); 96 | 97 | addr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_SHARED, fd2, 0); 98 | if (addr == MAP_FAILED) 99 | { 100 | perror("mmap failed"); 101 | exit(-1); 102 | } 103 | 104 | close(fd2); 105 | 106 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE; ++i) 107 | { 108 | if (addr[i] != buf[i]) 109 | { 110 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 111 | return 1; 112 | } 113 | } 114 | 115 | /* 116 | * Test 2: read from r/o mapping in child 117 | */ 118 | 119 | printf("Test 2\n"); 120 | 121 | TEST_FORK_BEGIN("child 1", 0, 0); 122 | { 123 | for (i = PAGE_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 124 | { 125 | if (addr[i] != buf[i]) 126 | { 127 | TEST_FORK_PRINTF("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 128 | return 1; 129 | } 130 | } 131 | 132 | return 0; 133 | } 134 | TEST_FORK_END(); 135 | 136 | for (i = 0; i < FILE_SIZE; ++i) 137 | { 138 | if (addr[i] != buf[i]) 139 | { 140 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 141 | return 1; 142 | } 143 | } 144 | 145 | /* 146 | * Test 3: write to r/o mapping from child (should fail) 147 | */ 148 | 149 | printf("Test 3\n"); 150 | 151 | #ifdef __OS2__ 152 | TEST_FORK_BEGIN("child 2", 0, SIGSEGV); 153 | #else 154 | TEST_FORK_BEGIN("child 2", 0, SIGBUS); 155 | #endif 156 | { 157 | /* Should crash here */ 158 | *addr = 1; 159 | 160 | return 1; 161 | } 162 | TEST_FORK_END(); 163 | 164 | if (munmap(addr, FILE_SIZE) == -1) 165 | { 166 | perror("munmap failed"); 167 | return 1; 168 | } 169 | 170 | free(fname); 171 | 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for beyond EOF mmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __OS2__ 32 | #include 33 | #endif 34 | 35 | /* 36 | * @todo For now we can't access beyond EOF for more than within 37 | * the last page. See https://github.com/bitwiseworks/libcx/issues/20 38 | * for details. 39 | */ 40 | #define MAP_SIZE 4096 41 | 42 | static int do_test(void); 43 | #define TEST_FUNCTION do_test () 44 | #include "../test-skeleton.c" 45 | 46 | static int 47 | do_test (void) 48 | { 49 | int rc; 50 | int n; 51 | unsigned char *addr; 52 | char *fname; 53 | struct stat st; 54 | char ch; 55 | 56 | int fd = create_temp_file("tst-mmap4-", &fname); 57 | if (fd == -1) 58 | { 59 | perror("create_temp_file failed"); 60 | return 1; 61 | } 62 | 63 | #ifdef __OS2__ 64 | setmode (fd, O_BINARY); 65 | #endif 66 | 67 | if (TEMP_FAILURE_RETRY((n = write(fd, "1", 1))) != 1) 68 | { 69 | if (n != -1) 70 | printf("write failed (write %d bytes instead of %d)\n", n, 1); 71 | else 72 | perror("write failed"); 73 | return 1; 74 | } 75 | 76 | /* 77 | * Test 1: shared mmap read beyond EOF (should return 0) 78 | */ 79 | 80 | printf("Test 1\n"); 81 | 82 | addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 83 | if (addr == MAP_FAILED) 84 | { 85 | perror("mmap failed"); 86 | return 1; 87 | } 88 | 89 | close(fd); 90 | 91 | if (addr[0] != '1') 92 | { 93 | printf("addr[0] is %u, must be %u\n", addr[0], '1'); 94 | return 1; 95 | } 96 | 97 | if (addr[1] != 0) 98 | { 99 | printf("addr[1] is %u, must be %u\n", addr[1], 0); 100 | return 1; 101 | } 102 | 103 | if (addr[MAP_SIZE - 1] != 0) 104 | { 105 | printf("addr[MAP_SIZE-1] is %u, must be %u\n", addr[MAP_SIZE - 1], 0); 106 | return 1; 107 | } 108 | 109 | /* 110 | * Test 2: shared mmap write beyond EOF (should not be synced back to file) 111 | */ 112 | 113 | printf("Test 2\n"); 114 | 115 | addr[0] = '2'; /* this is just to cause a flush for tracing */ 116 | 117 | addr[MAP_SIZE - 1] = '2'; 118 | 119 | if (addr[MAP_SIZE - 1] != '2') 120 | { 121 | printf("addr[MAP_SIZE-1] is %u, must be %u\n", addr[MAP_SIZE - 1], '2'); 122 | return 1; 123 | } 124 | 125 | if (munmap(addr, MAP_SIZE) == -1) 126 | { 127 | perror("munmap failed"); 128 | return 1; 129 | } 130 | 131 | fd = open(fname, O_RDONLY); 132 | if (fd == -1) 133 | { 134 | perror("open failed"); 135 | return 1; 136 | } 137 | 138 | #ifdef __OS2__ 139 | setmode (fd, O_BINARY); 140 | #endif 141 | 142 | if (fstat(fd, &st)) 143 | { 144 | perror("fstat failed"); 145 | return 1; 146 | } 147 | 148 | if (st.st_size != 1) 149 | { 150 | printf("file size is %lld, must be %d\n", (uint64_t) st.st_size, 1); 151 | return 1; 152 | } 153 | 154 | if (TEMP_FAILURE_RETRY((n = read(fd, &ch, 1))) != 1) 155 | { 156 | if (n != -1) 157 | printf("read failed (read %d bytes instead of %d)\n", n, 1); 158 | else 159 | perror("read failed"); 160 | return 1; 161 | } 162 | 163 | if (st.st_size != 1) 164 | { 165 | printf("ch is %u, must be %u\n", ch, '2'); 166 | return 1; 167 | } 168 | 169 | /* 170 | * Test 3: shared mmap read far beyond EOF (should crash) 171 | */ 172 | 173 | printf("Test 3\n"); 174 | 175 | #ifdef __OS2__ 176 | TEST_FORK_BEGIN("child", 0, SIGSEGV); 177 | #else 178 | TEST_FORK_BEGIN("child", 0, SIGBUS); 179 | #endif 180 | { 181 | addr = mmap(NULL, MAP_SIZE * 2, PROT_READ, MAP_SHARED, fd, 0); 182 | if (addr == MAP_FAILED) 183 | { 184 | perror("mmap failed"); 185 | return 1; 186 | } 187 | 188 | TEST_FORK_PRINTF("%d\n", addr[MAP_SIZE]); 189 | } 190 | TEST_FORK_END(); 191 | 192 | close(fd); 193 | 194 | free(fname); 195 | 196 | return 0; 197 | } 198 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for mmap + pread. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 2) 39 | 40 | unsigned char buf[FILE_SIZE]; 41 | 42 | static int do_test(void); 43 | #define TEST_FUNCTION do_test () 44 | #include "../test-skeleton.c" 45 | 46 | static int 47 | do_test (void) 48 | { 49 | int rc; 50 | int i, n; 51 | unsigned char *addr; 52 | char *fname; 53 | 54 | int fd = create_temp_file("tst-mmap5-1-", &fname); 55 | if (fd == -1) 56 | { 57 | perror("create_temp_file failed"); 58 | return 1; 59 | } 60 | 61 | #ifdef __OS2__ 62 | setmode (fd, O_BINARY); 63 | #endif 64 | 65 | srand(getpid()); 66 | 67 | for (i = 0; i < FILE_SIZE; ++i) 68 | buf[i] = rand() % 255; 69 | 70 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 71 | { 72 | if (n != -1) 73 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 74 | else 75 | perror("write failed"); 76 | return 1; 77 | } 78 | 79 | int fd2 = create_temp_file("tst-mmap5-2-", NULL); 80 | if (fd2 == -1) 81 | { 82 | perror("create_temp_file failed"); 83 | return 1; 84 | } 85 | 86 | #ifdef __OS2__ 87 | setmode (fd2, O_BINARY); 88 | #endif 89 | 90 | rc = ftruncate(fd2, FILE_SIZE); 91 | if (rc == -1) 92 | { 93 | perror("ftruncate failed"); 94 | return 1; 95 | } 96 | 97 | /* 98 | * Test 1: simple mmap 99 | */ 100 | 101 | printf("Test 1\n"); 102 | 103 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0); 104 | if (addr == MAP_FAILED) 105 | { 106 | perror("mmap failed"); 107 | return 1; 108 | } 109 | 110 | n = pread(fd, addr, FILE_SIZE, 0); 111 | 112 | if (n != FILE_SIZE) 113 | { 114 | if (n != -1) 115 | printf ("pread failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 116 | else 117 | perror("pread failed"); 118 | return 1; 119 | } 120 | 121 | for (i = 0; i < FILE_SIZE; ++i) 122 | { 123 | if (addr[i] != buf[i]) 124 | { 125 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 126 | return 1; 127 | } 128 | } 129 | 130 | if (munmap(addr, FILE_SIZE) == -1) 131 | { 132 | perror("munmap failed"); 133 | return 1; 134 | } 135 | 136 | free(fname); 137 | 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap6.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for two shared mmaps (samba). 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | /* 23 | * Inspired by http://trac.netlabs.org/samba/browser/trunk/server/lib/replace/test/shared_mmap.c 24 | */ 25 | 26 | #ifdef __OS2__ 27 | #define INCL_BASE 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __OS2__ 40 | #include 41 | #endif 42 | 43 | #ifndef PAGE_SIZE 44 | #define PAGE_SIZE 4096 45 | #endif 46 | 47 | #define FILE_SIZE (PAGE_SIZE * 2) 48 | #define TEST_VAL 255 49 | #define TEST_OFF1 0x123 50 | #define TEST_OFF2 (PAGE_SIZE + TEST_OFF1) 51 | 52 | unsigned char buf[FILE_SIZE]; 53 | unsigned char buf2[FILE_SIZE]; 54 | 55 | static int do_test(void); 56 | #define TEST_FUNCTION do_test () 57 | #include "../test-skeleton.c" 58 | 59 | static int 60 | do_test (void) 61 | { 62 | int rc; 63 | int i, n; 64 | unsigned char *addr; 65 | char *fname; 66 | int count = 60; 67 | 68 | int fd = create_temp_file("tst-mmap6-", &fname); 69 | if (fd == -1) 70 | { 71 | perror("create_temp_file failed"); 72 | return 1; 73 | } 74 | 75 | #ifdef __OS2__ 76 | /* 77 | * It turns out that open() is not multiprocess-safe on OS/2 meaning that if 78 | * two open calls of the same file happen at the same time in two different 79 | * kLIBC processes, one of them is likely to fail with `EACCES` (which breaks 80 | * this test). Protect against it with a mutex. 81 | * See http://trac.netlabs.org/libc/ticket/373 for more details. 82 | */ 83 | HMTX hmtx; 84 | APIRET arc = DosCreateMutexSem(NULL, &hmtx, DC_SEM_SHARED, FALSE); 85 | if (arc) 86 | { 87 | printf("DosCreateMutexSem failed with %ld\n", arc); 88 | return 1; 89 | } 90 | 91 | setmode (fd, O_BINARY); 92 | #endif 93 | 94 | srand(getpid()); 95 | 96 | for (i = 0; i < FILE_SIZE; ++i) 97 | buf[i] = rand() % 255; 98 | 99 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 100 | { 101 | if (n != -1) 102 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 103 | else 104 | perror("write failed"); 105 | return 1; 106 | } 107 | 108 | forget_temp_file(fname, fd); 109 | close(fd); 110 | 111 | /* 112 | * Test 1 113 | */ 114 | 115 | printf("Test 1\n"); 116 | 117 | if ((rc = fork()) == 0) 118 | { 119 | #ifdef __OS2__ 120 | arc = DosOpenMutexSem(NULL, &hmtx); 121 | if (arc) 122 | { 123 | printf("child: DosOpenMutexSem failed with %ld\n", arc); 124 | return 1; 125 | } 126 | arc = DosRequestMutexSem(hmtx, SEM_INDEFINITE_WAIT); 127 | if (arc) 128 | { 129 | printf("child: DosRequestMutexSem failed with %ld\n", arc); 130 | return 1; 131 | } 132 | #endif 133 | fd = open(fname, O_RDWR); 134 | #ifdef __OS2__ 135 | DosReleaseMutexSem(hmtx); 136 | #endif 137 | if (fd == -1) 138 | { 139 | perror("child: open failed"); 140 | return 1; 141 | } 142 | #ifdef __OS2__ 143 | setmode (fd, O_BINARY); 144 | #endif 145 | 146 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); 147 | if (addr == MAP_FAILED) 148 | { 149 | perror("child: mmap failed"); 150 | return 1; 151 | } 152 | 153 | while (count-- && addr[TEST_OFF1] != TEST_VAL) 154 | sleep(1); 155 | 156 | if (count <= 0) 157 | { 158 | printf("child: failed, count = %d\n", count); 159 | return 1; 160 | } 161 | 162 | printf("child: before writing test value\n"); 163 | addr[TEST_OFF2] = TEST_VAL; 164 | printf("child: after writing test value\n"); 165 | 166 | return 0; 167 | } 168 | 169 | if (rc < 0) 170 | { 171 | perror("fork"); 172 | return 1; 173 | } 174 | 175 | #ifdef __OS2__ 176 | arc = DosRequestMutexSem(hmtx, SEM_INDEFINITE_WAIT); 177 | if (arc) 178 | { 179 | printf("DosRequestMutexSem failed with %ld\n", arc); 180 | return 1; 181 | } 182 | #endif 183 | fd = open(fname, O_RDWR); 184 | #ifdef __OS2__ 185 | DosReleaseMutexSem(hmtx); 186 | #endif 187 | if (fd == -1) 188 | { 189 | perror("open failed"); 190 | return 1; 191 | } 192 | #ifdef __OS2__ 193 | setmode (fd, O_BINARY); 194 | #endif 195 | 196 | addr = mmap(NULL, FILE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); 197 | if (addr == MAP_FAILED) 198 | { 199 | perror("mmap failed"); 200 | return 1; 201 | } 202 | 203 | printf("parent: before writing test value\n"); 204 | addr[TEST_OFF1] = TEST_VAL; 205 | printf("parent: after writing test value\n"); 206 | 207 | while (count-- && addr[TEST_OFF2] != TEST_VAL) 208 | sleep(1); 209 | 210 | if (count <= 0) 211 | { 212 | printf("parent: failed, count = %d\n", count); 213 | return 1; 214 | } 215 | 216 | if (munmap(addr, FILE_SIZE * 2) == -1) 217 | { 218 | perror("munmap failed"); 219 | return 1; 220 | } 221 | 222 | close(fd); 223 | 224 | int status; 225 | if (wait(&status) == -1) 226 | { 227 | perror("wait failed"); 228 | return 1; 229 | } 230 | 231 | /* Now read the file and see if the contents matches our changes */ 232 | 233 | fd = open(fname, O_RDONLY); 234 | if (fd == -1) 235 | { 236 | perror("open failed"); 237 | return 1; 238 | } 239 | #ifdef __OS2__ 240 | setmode (fd, O_BINARY); 241 | #endif 242 | 243 | if (TEMP_FAILURE_RETRY((n = read(fd, buf2, FILE_SIZE))) != FILE_SIZE) 244 | { 245 | if (n != -1) 246 | printf("read failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 247 | else 248 | perror("read failed"); 249 | return 1; 250 | } 251 | 252 | for (i = 0; i < FILE_SIZE; ++i) 253 | { 254 | if (i == TEST_OFF1 || i == TEST_OFF2) 255 | { 256 | if (buf2[i] != TEST_VAL) 257 | { 258 | printf("buf2[0x%x] is %u, must be %u\n", i, buf2[i], TEST_VAL); 259 | return 1; 260 | } 261 | } 262 | else if (buf2[i] != buf[i]) 263 | { 264 | printf("buf2[0x%x] is %u, must be %u\n", i, buf2[i], buf[i]); 265 | return 1; 266 | } 267 | } 268 | 269 | close(fd); 270 | 271 | if (remove(fname)) 272 | { 273 | perror("remove failed"); 274 | return 1; 275 | } 276 | 277 | free(fname); 278 | 279 | return 0; 280 | } 281 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap7.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for partial/multiple mmap/munmap. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 4) 39 | 40 | unsigned char buf[FILE_SIZE]; 41 | 42 | static int do_test(void); 43 | #define TEST_FUNCTION do_test () 44 | #include "../test-skeleton.c" 45 | 46 | static int 47 | do_test (void) 48 | { 49 | int rc; 50 | int i, n, off; 51 | unsigned char *addr1, *addr2, *addr3; 52 | char *fname; 53 | 54 | int fd = create_temp_file("tst-mmap7-1-", &fname); 55 | if (fd == -1) 56 | { 57 | perror("create_temp_file failed"); 58 | return 1; 59 | } 60 | 61 | #ifdef __OS2__ 62 | setmode (fd, O_BINARY); 63 | #endif 64 | 65 | srand(getpid()); 66 | 67 | for (i = 0; i < FILE_SIZE; ++i) 68 | buf[i] = rand() % 255; 69 | 70 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 71 | { 72 | if (n != -1) 73 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 74 | else 75 | perror("write failed"); 76 | return 1; 77 | } 78 | 79 | for (n = 1; n <= 4; ++n) 80 | { 81 | TEST_FORK_BEGIN("child", 0, n < 3 ? 0 : SIGSEGV); 82 | { 83 | TEST_FORK_PRINTF("Test loop %d\n", n); 84 | int flags = (n == 1 || n == 3) ? MAP_SHARED : MAP_PRIVATE; 85 | 86 | /* 87 | * Test 1: create several file mappings 88 | */ 89 | 90 | TEST_FORK_PRINTF("Test 1.1\n"); 91 | 92 | off = 0; 93 | addr1 = mmap(NULL, 10, PROT_READ | PROT_WRITE, flags, fd, off); 94 | if (addr1 == MAP_FAILED) 95 | { 96 | TEST_FORK_PERROR("mmap failed"); 97 | return 1; 98 | } 99 | 100 | for (i = 0; i < PAGE_SIZE; ++i) 101 | { 102 | if (addr1[i - off] != buf[i]) 103 | { 104 | TEST_FORK_PRINTF("addr1[%d] is %u, must be %u\n", i - off, addr1[i - off], buf[i]); 105 | return 1; 106 | } 107 | } 108 | 109 | TEST_FORK_PRINTF("Test 1.2\n"); 110 | 111 | off = PAGE_SIZE * 2; 112 | addr2 = mmap(NULL, 20, PROT_READ | PROT_WRITE, flags, fd, off); 113 | if (addr2 == MAP_FAILED) 114 | { 115 | TEST_FORK_PERROR("mmap failed"); 116 | return 1; 117 | } 118 | 119 | for (i = off; i < off + PAGE_SIZE; ++i) 120 | { 121 | if (addr2[i - off] != buf[i]) 122 | { 123 | TEST_FORK_PRINTF("addr2[%d] is %u, must be %u\n", i - off, addr2[i - off], buf[i]); 124 | return 1; 125 | } 126 | } 127 | 128 | TEST_FORK_PRINTF("Test 1.3\n"); 129 | 130 | off = PAGE_SIZE; 131 | addr3 = mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, flags, fd, off); 132 | if (addr3 == MAP_FAILED) 133 | { 134 | TEST_FORK_PERROR("mmap failed"); 135 | return 1; 136 | } 137 | 138 | for (i = off; i < off + PAGE_SIZE; ++i) 139 | { 140 | if (addr3[i - off] != buf[i]) 141 | { 142 | TEST_FORK_PRINTF("addr3[%d] is %u, must be %u\n", i - off, addr3[i - off], buf[i]); 143 | return 1; 144 | } 145 | } 146 | 147 | /* 148 | * Test 2: unmap several regions 149 | */ 150 | 151 | TEST_FORK_PRINTF("Test 2\n"); 152 | 153 | if (munmap(addr3, PAGE_SIZE) == -1) 154 | { 155 | TEST_FORK_PERROR("munmap failed"); 156 | return 1; 157 | } 158 | 159 | if (munmap(addr1, FILE_SIZE) == -1) 160 | { 161 | TEST_FORK_PERROR("munmap failed"); 162 | return 1; 163 | } 164 | 165 | if (n < 3) 166 | return 0; 167 | 168 | /* Test 3: write somewhere (should crash) */ 169 | 170 | TEST_FORK_PRINTF("Test 3\n"); 171 | *addr1 = 0; 172 | } 173 | TEST_FORK_END(); 174 | } 175 | 176 | free(fname); 177 | 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /src/mmap/tst-mmap8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for overlapped mappings of the same file. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __OS2__ 31 | #include 32 | #endif 33 | 34 | #ifndef PAGE_SIZE 35 | #define PAGE_SIZE 4096 36 | #endif 37 | 38 | #define FILE_SIZE (PAGE_SIZE * 4) 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | unsigned char buf[FILE_SIZE]; 43 | 44 | static int do_test(void); 45 | #define TEST_FUNCTION do_test () 46 | #include "../test-skeleton.c" 47 | 48 | static int 49 | do_test (void) 50 | { 51 | int rc; 52 | int i, n; 53 | unsigned char *addr1, *addr2; 54 | char *fname; 55 | 56 | int fd = create_temp_file("tst-mmap8-", &fname); 57 | if (fd == -1) 58 | { 59 | perror("create_temp_file failed"); 60 | return 1; 61 | } 62 | 63 | #ifdef __OS2__ 64 | setmode (fd, O_BINARY); 65 | #endif 66 | 67 | srand(getpid()); 68 | 69 | for (i = 0; i < FILE_SIZE; ++i) 70 | buf[i] = rand() % 255; 71 | 72 | if (TEMP_FAILURE_RETRY((n = write(fd, buf, FILE_SIZE))) != FILE_SIZE) 73 | { 74 | if (n != -1) 75 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 76 | else 77 | perror("write failed"); 78 | return 1; 79 | } 80 | 81 | /* 82 | * Test 1: given these pages [0][1][2][3], first map 2-3, then map 1-2, 83 | * then unmap 2-3, then access page 2. It must work. 84 | */ 85 | 86 | printf("Test 1\n"); 87 | 88 | addr1 = mmap(NULL, PAGE_SIZE * 2, PROT_READ, MAP_SHARED, fd, PAGE_SIZE * 2); 89 | if (addr1 == MAP_FAILED) 90 | { 91 | perror("mmap failed"); 92 | return 1; 93 | } 94 | 95 | printf("addr1 = %p\n", addr1); 96 | 97 | addr2 = mmap(NULL, PAGE_SIZE * 2, PROT_READ, MAP_SHARED, fd, PAGE_SIZE); 98 | if (addr2 == MAP_FAILED) 99 | { 100 | perror("mmap failed"); 101 | return 1; 102 | } 103 | 104 | printf("addr2 = %p\n", addr2); 105 | 106 | if (munmap(addr1, PAGE_SIZE * 2) == -1) 107 | { 108 | perror("munmap failed"); 109 | return 1; 110 | } 111 | 112 | printf("addr2[0] = %hhu\n", addr2[0]); 113 | printf("addr2[PAGE_SIZE] = %hhu\n", addr2[PAGE_SIZE]); 114 | 115 | if (munmap(addr2, PAGE_SIZE * 2) == -1) 116 | { 117 | perror("munmap failed"); 118 | return 1; 119 | } 120 | 121 | free(fname); 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /src/mmap/tst-msync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for automatic mmap sync. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifdef __OS2__ 28 | #include 29 | #endif 30 | #include 31 | #include 32 | 33 | #include <../shared.h> 34 | 35 | #ifndef PAGE_SIZE 36 | #define PAGE_SIZE 4096 37 | #endif 38 | 39 | #define FILE_SIZE (PAGE_SIZE * 2) 40 | #define TEST_SIZE 10 41 | #define TEST_VAL 255 42 | 43 | /* Shared mapping file flush interval in ms (must match one from mmap.h) */ 44 | #define FLUSH_DELAY 1000 45 | 46 | unsigned char buf[FILE_SIZE]; 47 | unsigned char buf_chk[FILE_SIZE]; 48 | unsigned char buf2[TEST_SIZE * 2]; 49 | 50 | static int do_test(void); 51 | #define TEST_FUNCTION do_test () 52 | #include "../test-skeleton.c" 53 | 54 | static int 55 | do_test (void) 56 | { 57 | int rc; 58 | int i, n; 59 | unsigned char *addr; 60 | char *fname; 61 | int status; 62 | 63 | int fd = create_temp_file("tst-msync-", &fname); 64 | if (fd == -1) 65 | { 66 | puts("create_temp_file failed"); 67 | return 1; 68 | } 69 | 70 | #ifdef __OS2__ 71 | setmode(fd, O_BINARY); 72 | #endif 73 | 74 | srand(getpid()); 75 | 76 | for (i = 0; i < FILE_SIZE; ++i) 77 | buf[i] = rand() % 255; 78 | 79 | if ((n = write(fd, buf, FILE_SIZE)) != FILE_SIZE) 80 | { 81 | if (n != -1) 82 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 83 | else 84 | perror("write failed"); 85 | return 1; 86 | } 87 | 88 | /* 89 | * Test 1: create shared mmap, modify it from child (while letting parent go) 90 | * and make sure that changes are flushed to disk after FLUSH_DELAY 91 | */ 92 | 93 | printf("Test 1\n"); 94 | 95 | addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 96 | if (addr == MAP_FAILED) 97 | { 98 | perror("mmap failed"); 99 | exit(-1); 100 | } 101 | 102 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 103 | { 104 | if (addr[i] != buf[i]) 105 | { 106 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 107 | return 1; 108 | } 109 | } 110 | 111 | switch (fork()) 112 | { 113 | case -1: 114 | perror("fork failed"); 115 | exit(-1); 116 | 117 | case 0: 118 | { 119 | /* Let the parent end first */ 120 | sleep(1); 121 | 122 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 123 | { 124 | if (addr[i] != buf[i]) 125 | { 126 | printf("child: addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 127 | return 1; 128 | } 129 | } 130 | 131 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 132 | addr[i] = TEST_VAL; 133 | 134 | /* Let mmap auto-sync code flush changed memory back to the file */ 135 | usleep((FLUSH_DELAY * 2 + 500) * 1000); 136 | 137 | /* Now check the file contents */ 138 | if (lseek(fd, 0, SEEK_SET) == -1) 139 | { 140 | perror("lseek failed"); 141 | return 1; 142 | } 143 | 144 | if ((n = read(fd, buf_chk, FILE_SIZE)) != FILE_SIZE) 145 | { 146 | if (n != -1) 147 | printf("read failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 148 | else 149 | perror("read failed"); 150 | return 1; 151 | } 152 | 153 | for (i = 0; i < FILE_SIZE; ++i) 154 | { 155 | if (addr[i] != buf_chk[i]) 156 | { 157 | printf("buf_chk[%d] is %u, must be %u\n", i, buf_chk[i], addr[i]); 158 | return 1; 159 | } 160 | } 161 | 162 | if (munmap(addr, FILE_SIZE) == -1) 163 | { 164 | perror("child: munmap failed"); 165 | return 1; 166 | } 167 | 168 | return 0; 169 | } 170 | } 171 | 172 | if (munmap(addr, FILE_SIZE) == -1) 173 | { 174 | perror("munmap failed"); 175 | return 1; 176 | } 177 | 178 | #ifdef DEBUG 179 | /* 180 | * Force this process LIBCx usage termination to simulate the parent process 181 | * termination before the forked child. Simulation is needed because we want 182 | * the child exit code so can't really terminate w/o calling wait(). Note 183 | * that we use _std_wait directly as we override wait and need global_lock() 184 | * there (see also below). 185 | */ 186 | force_libcx_term(); 187 | #endif 188 | 189 | rc = 0; 190 | 191 | extern pid_t _std_wait(int *); 192 | if (_std_wait(&status) == -1) 193 | { 194 | perror("wait failed"); 195 | rc = 1; 196 | } 197 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 198 | { 199 | printf("child crashed or returned non-zero (status %x)\n", status); 200 | rc = 1; 201 | } 202 | 203 | #ifdef DEBUG 204 | /* 205 | * Now restore the initialized state to avoid crashes due to calls to 206 | * global_lock() from close() and other overrides from atexit() callbacks. 207 | */ 208 | force_libcx_init(); 209 | #endif 210 | 211 | return rc; 212 | } 213 | -------------------------------------------------------------------------------- /src/mmap/tst-msync3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for msync. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifdef __OS2__ 28 | #include 29 | #endif 30 | #include 31 | #include 32 | 33 | #ifndef PAGE_SIZE 34 | #define PAGE_SIZE 4096 35 | #endif 36 | 37 | #define FILE_SIZE (PAGE_SIZE * 2) 38 | #define FILE_VAL 1 39 | #define TEST_SIZE 10 40 | #define TEST_VAL 255 41 | 42 | /* Shared mapping file flush interval in ms (must match one from mmap.h) */ 43 | #define FLUSH_DELAY 1000 44 | 45 | unsigned char buf[FILE_SIZE]; 46 | unsigned char buf_chk[FILE_SIZE]; 47 | unsigned char buf2[TEST_SIZE * 2]; 48 | 49 | static int do_test(void); 50 | #define TEST_FUNCTION do_test () 51 | #include "../test-skeleton.c" 52 | 53 | static int 54 | do_test (void) 55 | { 56 | int rc; 57 | int i, n; 58 | unsigned char *addr; 59 | char *fname; 60 | int status; 61 | 62 | int fd = create_temp_file("tst-msync3-", &fname); 63 | if (fd == -1) 64 | { 65 | puts("create_temp_file failed"); 66 | return 1; 67 | } 68 | 69 | #ifdef __OS2__ 70 | setmode(fd, O_BINARY); 71 | #endif 72 | 73 | for (i = 0; i < FILE_SIZE; ++i) 74 | buf[i] = FILE_VAL; 75 | 76 | if ((n = write(fd, buf, FILE_SIZE)) != FILE_SIZE) 77 | { 78 | if (n != -1) 79 | printf("write failed (write %d bytes instead of %d)\n", n, FILE_SIZE); 80 | else 81 | perror("write failed"); 82 | return 1; 83 | } 84 | 85 | /* 86 | * Test 1: create shared mmap, modify it, msync it synchronously and make sure 87 | * that changes are flushed to disk. Note that we only use PROT_WRITE to also 88 | * test how it behaves without PAG_READ (which is implied in such a case). 89 | */ 90 | 91 | printf("Test 1\n"); 92 | 93 | addr = mmap(NULL, FILE_SIZE, PROT_WRITE, MAP_SHARED, fd, 0); 94 | if (addr == MAP_FAILED) 95 | { 96 | perror("mmap failed"); 97 | exit(-1); 98 | } 99 | 100 | for (i = 0; i < FILE_SIZE; ++i) 101 | { 102 | if (addr[i] != buf[i]) 103 | { 104 | printf("addr[%d] is %u, must be %u\n", i, addr[i], buf[i]); 105 | return 1; 106 | } 107 | } 108 | 109 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 110 | addr[i] = TEST_VAL; 111 | 112 | // /* Let mmap auto-sync code flush changed memory back to the file */ 113 | // usleep((FLUSH_DELAY * 2 + 500) * 1000); 114 | 115 | /* Sync only the second page */ 116 | msync(addr + PAGE_SIZE, PAGE_SIZE, MS_SYNC); 117 | 118 | /* Now check the file contents */ 119 | if (lseek(fd, 0, SEEK_SET) == -1) 120 | { 121 | perror("lseek failed"); 122 | return 1; 123 | } 124 | 125 | if ((n = read(fd, buf_chk, FILE_SIZE)) != FILE_SIZE) 126 | { 127 | if (n != -1) 128 | printf("read failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 129 | else 130 | perror("read failed"); 131 | return 1; 132 | } 133 | 134 | /* The second page must be TEST_VAL */ 135 | for (i = PAGE_SIZE; i < PAGE_SIZE * 2; ++i) 136 | { 137 | if (addr[i] != buf_chk[i]) 138 | { 139 | printf("buf_chk[%d] is %u, must be %u\n", i, buf_chk[i], addr[i]); 140 | return 1; 141 | } 142 | } 143 | 144 | /* The first page must be initial val */ 145 | for (i = 0; i < PAGE_SIZE; ++i) 146 | { 147 | if (buf[i] != buf_chk[i]) 148 | { 149 | printf("buf_chk[%d] is %u, must be %u\n", i, buf_chk[i], buf[i]); 150 | return 1; 151 | } 152 | } 153 | 154 | /* 155 | * Test 2: change more bytes and msync it asynchronously, then let the 156 | * async sync run, then check the file 157 | */ 158 | 159 | printf("Test 2\n"); 160 | 161 | for (i = PAGE_SIZE - TEST_SIZE; i < PAGE_SIZE + TEST_SIZE; ++i) 162 | addr[i] = buf[i]; 163 | 164 | /* Sync first page (all pages must actually sync) */ 165 | msync(addr, PAGE_SIZE, MS_ASYNC); 166 | 167 | /* let immediate async request get processed (delay must be < FLUSH_DELAY) */ 168 | usleep(100 * 1000); 169 | 170 | /* Now check the file contents */ 171 | if (lseek(fd, 0, SEEK_SET) == -1) 172 | { 173 | perror("lseek failed"); 174 | return 1; 175 | } 176 | 177 | if ((n = read(fd, buf_chk, FILE_SIZE)) != FILE_SIZE) 178 | { 179 | if (n != -1) 180 | printf("read failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 181 | else 182 | perror("read failed"); 183 | return 1; 184 | } 185 | 186 | for (i = 0; i < FILE_SIZE; ++i) 187 | { 188 | if (addr[i] != buf_chk[i]) 189 | { 190 | printf("buf_chk[%d] is %u, must be %u\n", i, buf_chk[i], addr[i]); 191 | return 1; 192 | } 193 | } 194 | 195 | if (munmap(addr, FILE_SIZE) == -1) 196 | { 197 | perror("child: munmap failed"); 198 | return 1; 199 | } 200 | 201 | return 0; 202 | } 203 | -------------------------------------------------------------------------------- /src/net/getifaddrs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * getifaddrs() implementation for OS/2 kLIBC 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | /* 23 | Unix SMB/CIFS implementation. 24 | Samba utility functions 25 | Copyright (C) Andrew Tridgell 1998 26 | Copyright (C) Jeremy Allison 2007 27 | Copyright (C) Jelmer Vernooij 2007 28 | 29 | ** NOTE! The following LGPL license applies to the replace 30 | ** library. This does NOT imply that all of Samba is released 31 | ** under the LGPL 32 | 33 | This library is free software; you can redistribute it and/or 34 | modify it under the terms of the GNU Lesser General Public 35 | License as published by the Free Software Foundation; either 36 | version 3 of the License, or (at your option) any later version. 37 | 38 | This library is distributed in the hope that it will be useful, 39 | but WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 41 | Library General Public License for more details. 42 | 43 | You should have received a copy of the GNU Lesser General Public 44 | License along with this library; if not, see . 45 | */ 46 | 47 | #include "libcx/net.h" 48 | #include "ifaddrs.h" 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | 62 | #define HAVE_SOCKADDR_SA_LEN 63 | #define rep_getifaddrs getifaddrs 64 | #define rep_freeifaddrs freeifaddrs 65 | 66 | #ifdef HAVE_SYS_TIME_H 67 | #include 68 | #endif 69 | 70 | #ifndef SIOCGIFCONF 71 | #ifdef HAVE_SYS_SOCKIO_H 72 | #include 73 | #endif 74 | #endif 75 | 76 | void rep_freeifaddrs(struct ifaddrs *ifp) 77 | { 78 | if (ifp != NULL) { 79 | free(ifp->ifa_name); 80 | free(ifp->ifa_addr); 81 | free(ifp->ifa_netmask); 82 | if (ifp->ifa_flags & IFF_BROADCAST) 83 | free(ifp->ifa_broadaddr); 84 | else if (ifp->ifa_flags & IFF_POINTOPOINT) 85 | free(ifp->ifa_dstaddr); 86 | freeifaddrs(ifp->ifa_next); 87 | free(ifp); 88 | } 89 | } 90 | 91 | static struct sockaddr *sockaddr_dup(struct sockaddr *sa) 92 | { 93 | struct sockaddr *ret; 94 | socklen_t socklen; 95 | #ifdef HAVE_SOCKADDR_SA_LEN 96 | socklen = sa->sa_len; 97 | #else 98 | socklen = sizeof(struct sockaddr_storage); 99 | #endif 100 | ret = calloc(1, socklen); 101 | if (ret == NULL) 102 | return NULL; 103 | memcpy(ret, sa, socklen); 104 | return ret; 105 | } 106 | 107 | /**************************************************************************** 108 | this one is for AIX (tested on 4.2) 109 | ****************************************************************************/ 110 | int rep_getifaddrs(struct ifaddrs **ifap) 111 | { 112 | char buff[8192]; 113 | int fd, i; 114 | struct ifconf ifc; 115 | struct ifreq *ifr=NULL; 116 | struct ifaddrs *curif; 117 | struct ifaddrs *lastif = NULL; 118 | 119 | *ifap = NULL; 120 | 121 | if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 122 | return -1; 123 | } 124 | 125 | ifc.ifc_len = sizeof(buff); 126 | ifc.ifc_buf = buff; 127 | 128 | if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { 129 | close(fd); 130 | return -1; 131 | } 132 | 133 | ifr = ifc.ifc_req; 134 | 135 | /* Loop through interfaces */ 136 | i = ifc.ifc_len; 137 | 138 | while (i > 0) { 139 | unsigned int inc; 140 | 141 | inc = ifr->ifr_addr.sa_len; 142 | 143 | curif = calloc(1, sizeof(struct ifaddrs)); 144 | if (lastif == NULL) { 145 | *ifap = curif; 146 | } else { 147 | lastif->ifa_next = curif; 148 | } 149 | 150 | curif->ifa_name = strdup(ifr->ifr_name); 151 | curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); 152 | curif->ifa_dstaddr = NULL; 153 | curif->ifa_data = NULL; 154 | curif->ifa_netmask = NULL; 155 | curif->ifa_next = NULL; 156 | 157 | if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { 158 | goto fail; 159 | } 160 | 161 | curif->ifa_flags = (unsigned short)ifr->ifr_flags; 162 | 163 | /* 164 | * The rest is requested only for AF_INET, for portability and 165 | * compatiblilty (see e.g. https://linux.die.net/man/7/netdevice) 166 | */ 167 | 168 | if (curif->ifa_addr->sa_family == AF_INET) { 169 | if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { 170 | goto fail; 171 | } 172 | curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); 173 | 174 | if (curif->ifa_flags & IFF_BROADCAST) { 175 | if (ioctl(fd, SIOCGIFBRDADDR, ifr) != 0) { 176 | goto fail; 177 | } 178 | /* 179 | * OS/2 TCP/IP 4.21 is known to leave this field zeroed but return the 180 | * correct address. We assume that it's so if ioctl succeeds and family 181 | * matches what it should be. 182 | */ 183 | if (ifr->ifr_broadaddr.sa_len == 0 && 184 | ifr->ifr_broadaddr.sa_family == curif->ifa_addr->sa_family) { 185 | ifr->ifr_broadaddr.sa_len = sizeof(struct sockaddr_in); 186 | } 187 | curif->ifa_broadaddr = sockaddr_dup(&ifr->ifr_broadaddr); 188 | } else if (curif->ifa_flags & IFF_POINTOPOINT) { 189 | if (ioctl(fd, SIOCGIFDSTADDR, ifr) != 0) { 190 | goto fail; 191 | } 192 | /* 193 | * OS/2 TCP/IP 4.21 is known to leave this field zeroed but return the 194 | * correct address. We assume that it's so if ioctl succeeds and family 195 | * matches what it should be. 196 | */ 197 | if (ifr->ifr_dstaddr.sa_len == 0 && 198 | ifr->ifr_dstaddr.sa_family == curif->ifa_addr->sa_family) { 199 | ifr->ifr_dstaddr.sa_len = sizeof(struct sockaddr_in); 200 | } 201 | curif->ifa_dstaddr = sockaddr_dup(&ifr->ifr_dstaddr); 202 | } 203 | } 204 | 205 | lastif = curif; 206 | 207 | /* 208 | * Patch from Archie Cobbs (archie@whistle.com). The 209 | * addresses in the SIOCGIFCONF interface list have a 210 | * minimum size. Usually this doesn't matter, but if 211 | * your machine has tunnel interfaces, etc. that have 212 | * a zero length "link address", this does matter. */ 213 | 214 | if (inc < sizeof(ifr->ifr_addr)) 215 | inc = sizeof(ifr->ifr_addr); 216 | inc += IFNAMSIZ; 217 | 218 | ifr = (struct ifreq*) (((char*) ifr) + inc); 219 | i -= inc; 220 | } 221 | 222 | close(fd); 223 | return 0; 224 | 225 | fail: 226 | close(fd); 227 | freeifaddrs(*ifap); 228 | return -1; 229 | } 230 | -------------------------------------------------------------------------------- /src/net/if_nameindex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * if_nameindex() family implementation for OS/2 kLIBC 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | /* 23 | * if_nameindex() family implementaiton for OS/2 kLIBC 24 | * 25 | * Copyright (C) 2016 KO Myung-Hun 26 | * 27 | * This program is free software. It comes without any warranty, to 28 | * the extent permitted by applicable law. You can redistribute it 29 | * and/or modify it under the terms of the Do What The Fuck You Want 30 | * To Public License, Version 2, as published by Sam Hocevar. See 31 | * http://www.wtfpl.net/ for more details. 32 | */ 33 | 34 | #include "libcx/net.h" 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include /* SIOCGIFCONF */ 43 | #include /* struct ifconf, struct ifreq */ 44 | #include /* struct sockaddr_dl */ 45 | 46 | struct if_nameindex *if_nameindex( void ) 47 | { 48 | int s; 49 | struct ifconf ifconf; 50 | struct ifreq iflist[ IFMIB_ENTRIES /* MAX 42 */]; 51 | struct if_nameindex *nis = NULL; 52 | int ifcount; 53 | int entries = 0; 54 | int i; 55 | 56 | s = socket( PF_INET, SOCK_RAW, 0 ); 57 | if( s == -1 ) 58 | goto out; 59 | 60 | /* Get all interfaces */ 61 | ifconf.ifc_len = sizeof( iflist ); 62 | ifconf.ifc_req = iflist; 63 | if( ioctl( s, SIOCGIFCONF, &ifconf )) 64 | goto out; 65 | 66 | /* Calculate count of returned interfaces */ 67 | ifcount = ifconf.ifc_len / sizeof( struct ifreq ); 68 | 69 | /* Allocate 1 more entry for the last mark */ 70 | nis = calloc( 1, sizeof( *nis ) * ( ifcount + 1 )); 71 | if( nis == NULL ) 72 | goto out; 73 | 74 | for( i = 0; i < ifcount; i++ ) 75 | { 76 | /* Find available interfaces */ 77 | if( iflist[ i ].ifr_addr.sa_family == AF_LINK ) 78 | { 79 | struct sockaddr_dl *sdl = 80 | ( struct sockaddr_dl * )&iflist[ i ].ifr_addr; 81 | 82 | nis[ entries ].if_index = sdl->sdl_index; 83 | nis[ entries ].if_name = strdup( iflist[ i ].ifr_name ); 84 | if( nis[ entries ].if_name == NULL ) 85 | { 86 | if_freenameindex( nis ); 87 | 88 | nis = NULL; 89 | 90 | goto out; 91 | } 92 | 93 | entries++; 94 | } 95 | } 96 | 97 | /* Last entry should be 0 and NULL. calloc() did it */ 98 | 99 | entries++; 100 | 101 | out: 102 | /* Shrink if needed */ 103 | if( nis != NULL && entries != ifcount ) 104 | nis = realloc( nis, sizeof( *nis ) * entries ); 105 | 106 | close( s ); 107 | 108 | return nis; 109 | } 110 | 111 | void if_freenameindex( struct if_nameindex *ptr ) 112 | { 113 | int i; 114 | 115 | if( ptr == NULL ) 116 | return; 117 | 118 | for( i = 0; ptr[ i ].if_index != 0; i++ ) 119 | free( ptr[ i ].if_name ); 120 | 121 | free( ptr ); 122 | } 123 | 124 | char *if_indextoname( unsigned ifindex, char *ifname ) 125 | { 126 | struct if_nameindex *nis; 127 | int i; 128 | 129 | nis = if_nameindex(); 130 | if( nis == NULL ) 131 | return NULL; 132 | 133 | for( i = 0; nis[ i ].if_index != 0; i++ ) 134 | { 135 | if( ifindex == nis[ i ].if_index ) 136 | { 137 | strcpy( ifname, nis[ i ].if_name ); 138 | 139 | break; 140 | } 141 | } 142 | 143 | i = nis[ i ].if_index; 144 | 145 | if_freenameindex( nis ); 146 | 147 | if( i == 0 ) 148 | return NULL; 149 | 150 | return ifname; 151 | } 152 | 153 | unsigned if_nametoindex( const char *ifname ) 154 | { 155 | struct if_nameindex *nis; 156 | int i; 157 | 158 | nis = if_nameindex(); 159 | if( nis == NULL ) 160 | return 0; 161 | 162 | for( i = 0; nis[ i ].if_index != 0; i++ ) 163 | { 164 | if( strcmp( ifname, nis[ i ].if_name ) == 0 ) 165 | break; 166 | } 167 | 168 | i = nis[ i ].if_index; 169 | 170 | if_freenameindex( nis ); 171 | 172 | return i; 173 | } 174 | -------------------------------------------------------------------------------- /src/net/ifaddrs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * network extensions for kLIBC. 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef IFADDRS_H 23 | #define IFADDRS_H 24 | 25 | #include 26 | 27 | struct ifaddrs { 28 | struct ifaddrs *ifa_next; /* Pointer to next struct */ 29 | char *ifa_name; /* Interface name */ 30 | unsigned int ifa_flags; /* Interface flags */ 31 | struct sockaddr *ifa_addr; /* Interface address */ 32 | struct sockaddr *ifa_netmask; /* Interface netmask */ 33 | union { 34 | struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */ 35 | struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */ 36 | } ifa_ifu; 37 | #define ifa_broadaddr ifa_ifu.ifu_broadaddr 38 | #define ifa_dstaddr ifa_ifu.ifu_dstaddr 39 | void *ifa_data; /* Address specific data */ 40 | }; 41 | 42 | __BEGIN_DECLS 43 | 44 | int getifaddrs(struct ifaddrs **ifap); 45 | void freeifaddrs(struct ifaddrs *ifa); 46 | 47 | __END_DECLS 48 | 49 | #endif /* IFADDRS_H */ 50 | -------------------------------------------------------------------------------- /src/net/libcx/net.h: -------------------------------------------------------------------------------- 1 | /* 2 | * network extensions for kLIBC. 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef LIBCX_NET_H 23 | #define LIBCX_NET_H 24 | 25 | /* 26 | * Definitions that originally belong to . 27 | * 28 | * Based on a mix of VLC and Samba headers for getaddrinfo API emulation. 29 | */ 30 | 31 | #include 32 | #include /* for socklen_t */ 33 | #include /* for IFNAMSIZ */ 34 | 35 | /* GAI error codes */ 36 | #define EAI_BADFLAGS -1 37 | #define EAI_NONAME -2 38 | #define EAI_AGAIN -3 39 | #define EAI_FAIL -4 40 | #define EAI_NODATA -5 41 | #define EAI_FAMILY -6 42 | #define EAI_SOCKTYPE -7 43 | #define EAI_SERVICE -8 44 | #define EAI_ADDRFAMILY -9 45 | #define EAI_MEMORY -10 46 | #define EAI_OVERFLOW -11 47 | #define EAI_SYSTEM -12 48 | 49 | #define NI_NUMERICHOST 0x01 50 | #define NI_NUMERICSERV 0x02 51 | #define NI_NOFQDN 0x04 52 | #define NI_NAMEREQD 0x08 53 | #define NI_DGRAM 0x10 54 | 55 | /* Borrowed from glibc as needed for linux apps */ 56 | #define NI_MAXHOST 1025 57 | #define NI_MAXSERV 32 58 | 59 | #define AI_PASSIVE 0x0001 60 | #define AI_CANONNAME 0x0002 61 | #define AI_NUMERICHOST 0x0004 62 | #define AI_NUMERICSERV 0x0400 63 | 64 | struct addrinfo 65 | { 66 | int ai_flags; 67 | int ai_family; 68 | int ai_socktype; 69 | int ai_protocol; 70 | size_t ai_addrlen; 71 | struct sockaddr *ai_addr; 72 | char *ai_canonname; 73 | struct addrinfo *ai_next; 74 | }; 75 | 76 | __BEGIN_DECLS 77 | 78 | const char *gai_strerror(int errnum); 79 | int getaddrinfo(const char *node, const char *service, 80 | const struct addrinfo *hints, struct addrinfo **res); 81 | void freeaddrinfo(struct addrinfo *res); 82 | int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, 83 | int hostlen, char *serv, int servlen, int flags); 84 | 85 | __END_DECLS 86 | 87 | /* 88 | * Definitions that originally belong to . 89 | * 90 | * Based on if_nameindex.h by KO Myung-Hun . 91 | */ 92 | 93 | #define IF_NAMESIZE IFNAMSIZ 94 | 95 | struct if_nameindex 96 | { 97 | /* Note: if_index may be different from ifmib.iftable.iftIndex */ 98 | unsigned int if_index; 99 | char *if_name; 100 | }; 101 | 102 | 103 | __BEGIN_DECLS 104 | 105 | struct if_nameindex *if_nameindex(void); 106 | void if_freenameindex(struct if_nameindex *ptr); 107 | char *if_indextoname(unsigned ifindex, char *ifname); 108 | unsigned if_nametoindex(const char *ifname); 109 | 110 | __END_DECLS 111 | 112 | #endif /* LIBCX_NET_H */ 113 | -------------------------------------------------------------------------------- /src/net/tst-getaddrinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for getaddrinfo API. 3 | * Copyright (C) 2017 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2017. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include "libcx/net.h" 33 | 34 | static int do_test(void); 35 | #define TEST_FUNCTION do_test() 36 | #include "../test-skeleton.c" 37 | 38 | static int do_test(void) 39 | { 40 | const char *bad_hostname = "nonexistent.comcom"; 41 | const char *hostname = "bitwiseworks.com"; 42 | int addr = (216 << 24) + (239 << 16) + (38 << 8) + 21; 43 | 44 | struct addrinfo hints; 45 | memset(&hints, 0, sizeof(hints)); 46 | hints.ai_family = PF_UNSPEC; 47 | hints.ai_flags = AI_CANONNAME; 48 | 49 | struct addrinfo *res = NULL; 50 | int rc = getaddrinfo(hostname, 0, &hints, &res); 51 | if (rc) 52 | perr_and(return 1, "getaddrinfo returned %d (%s) for [%s]", rc, gai_strerror(rc), hostname); 53 | if (!res) 54 | perr_and(return 1, "getaddrinfo returned null list for [%s]", hostname); 55 | 56 | struct sockaddr_in in_addr = *(struct sockaddr_in *)res->ai_addr; 57 | 58 | #if 0 59 | struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr; 60 | if (ntohl(in->sin_addr.s_addr) != addr) 61 | perr_and(return 1, "getaddrinfo returned address %x != %x", ntohl(in->sin_addr.s_addr), addr); 62 | #endif 63 | 64 | if (strcmp(res->ai_canonname, hostname)) 65 | perr_and(return 1, "getaddrinfo returned canonname [%s] != [%s]", res->ai_canonname, hostname); 66 | 67 | while (res) 68 | { 69 | struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr; 70 | printf("Family %d\nAddresss %0x\nFlags %x\nSocktype %d\nProtocol %d\nCanonical name [%s]\n\n", 71 | res->ai_family, 72 | ntohl(in->sin_addr.s_addr), 73 | res->ai_flags, 74 | res->ai_socktype, 75 | res->ai_protocol, 76 | res->ai_canonname); 77 | res = res->ai_next; 78 | } 79 | 80 | freeaddrinfo(res); 81 | 82 | rc = getaddrinfo(bad_hostname, 0, NULL, &res); 83 | if (!rc) 84 | perr_and(return 1, "getaddrinfo returned success for [%s]", bad_hostname); 85 | 86 | printf("Result for [%s] is %d (%s)\n", bad_hostname, rc, gai_strerror(rc)); 87 | 88 | struct sockaddr_in sa4; 89 | memset(&sa4, 0, sizeof(sa4)); 90 | sa4.sin_family = AF_INET; 91 | sa4.sin_addr.s_addr = in_addr.sin_addr.s_addr; 92 | sa4.sin_port = 80; 93 | 94 | char hostbuf[NI_MAXHOST] = ""; 95 | char servbuf[NI_MAXSERV] = ""; 96 | rc = getnameinfo((struct sockaddr *)&sa4, sizeof(sa4), hostbuf, sizeof(hostbuf), servbuf, sizeof(servbuf), 0); 97 | if (rc) 98 | perr_and(return 1, "getnameinfo returned %d (%s) for %x", rc, gai_strerror(rc), ntohl(in_addr.sin_addr.s_addr)); 99 | 100 | printf("host [%s] serv [%s]\n", hostbuf, servbuf); 101 | 102 | if (hostbuf[0] == '\0' || servbuf[0] == '\0') 103 | perr_and(return 1, "getnameinfo returned empty hostbuf or servbuf"); 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /src/net/tst-getifaddrs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for getifaddrs API. 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #include "libcx/net.h" 35 | #include "ifaddrs.h" 36 | 37 | static int do_test(void); 38 | #define TEST_FUNCTION do_test() 39 | #include "../test-skeleton.c" 40 | 41 | /* 42 | * This is a simplified (AF_INET only) and sligntly extended version of the 43 | * example from http://man7.org/linux/man-pages/man3/getifaddrs.3.html. 44 | */ 45 | 46 | static int do_test(void) 47 | { 48 | struct ifaddrs *ifaddr, *ifa; 49 | int family, s, n; 50 | char host[NI_MAXHOST]; 51 | 52 | if (getifaddrs(&ifaddr) == -1) { 53 | perrno_and(return 1, "getifaddrs"); 54 | } 55 | 56 | /* Walk through linked list, maintaining head pointer so we 57 | can free list later */ 58 | 59 | for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { 60 | if (ifa->ifa_addr == NULL) 61 | continue; 62 | 63 | family = ifa->ifa_addr->sa_family; 64 | 65 | /* Display interface name and family (including symbolic 66 | form of the latter for the common families) */ 67 | 68 | printf("%-8s %s (%d)\n", 69 | ifa->ifa_name, 70 | (family == AF_LINK) ? "AF_LINK" : 71 | (family == AF_INET) ? "AF_INET" : "???", 72 | family); 73 | 74 | /* For an AF_INET* interface address, display the address */ 75 | 76 | if (family == AF_INET) { 77 | s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), 78 | host, NI_MAXHOST, 79 | NULL, 0, NI_NUMERICHOST); 80 | if (s != 0) { 81 | printf("getnameinfo() failed: %s\n", gai_strerror(s)); 82 | exit(EXIT_FAILURE); 83 | } 84 | printf("\t\taddress: <%s>\n", host); 85 | s = getnameinfo(ifa->ifa_netmask, sizeof(struct sockaddr_in), 86 | host, NI_MAXHOST, 87 | NULL, 0, NI_NUMERICHOST); 88 | if (s != 0) { 89 | printf("getnameinfo() failed: %s\n", gai_strerror(s)); 90 | exit(EXIT_FAILURE); 91 | } 92 | printf("\t\tnetmask: <%s>\n", host); 93 | if (ifa->ifa_flags & IFF_BROADCAST) { 94 | s = getnameinfo(ifa->ifa_broadaddr, sizeof(struct sockaddr_in), 95 | host, NI_MAXHOST, 96 | NULL, 0, NI_NUMERICHOST); 97 | if (s != 0) { 98 | printf("getnameinfo() failed: %s\n", gai_strerror(s)); 99 | exit(EXIT_FAILURE); 100 | } 101 | printf("\t\tbroadcast address: <%s>\n", host); 102 | } else if (ifa->ifa_flags & IFF_POINTOPOINT) { 103 | s = getnameinfo(ifa->ifa_dstaddr, sizeof(struct sockaddr_in), 104 | host, NI_MAXHOST, 105 | NULL, 0, NI_NUMERICHOST); 106 | if (s != 0) { 107 | printf("getnameinfo() failed: %s\n", gai_strerror(s)); 108 | exit(EXIT_FAILURE); 109 | } 110 | printf("\t\tP2P address: <%s>\n", host); 111 | } 112 | } else if (family == AF_LINK) { 113 | struct sockaddr_dl * dl = (struct sockaddr_dl *)ifa->ifa_addr; 114 | printf("\t\tinterface index: <%d>\n", dl->sdl_index); 115 | printf("\t\tinterface type: <0x%x>\n", dl->sdl_type); 116 | printf("\t\tinterface name: <%.*s>\n", dl->sdl_nlen, dl->sdl_data); 117 | if (dl->sdl_alen) { 118 | printf("\t\tlink address: <"); 119 | int n; 120 | for (n = 0; n < dl->sdl_alen; ++n) 121 | printf("%02X%s", (unsigned char) *(dl->sdl_data + dl->sdl_nlen + n), 122 | n == dl->sdl_alen - 1 ? ">\n" : ":"); 123 | } 124 | } 125 | printf("\t\tflags: <0x%x>\n", ifa->ifa_flags); 126 | } 127 | 128 | freeifaddrs(ifaddr); 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /src/net/tst-nameindex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for if_nameindex API. 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "libcx/net.h" 28 | 29 | static int do_test(void); 30 | #define TEST_FUNCTION do_test() 31 | #include "../test-skeleton.c" 32 | 33 | /* 34 | * This is a sligntly extended version of the example from 35 | * http://man7.org/linux/man-pages/man3/if_nameindex.3.html. 36 | */ 37 | 38 | static int do_test(void) 39 | { 40 | printf("Test 1\n"); 41 | 42 | struct if_nameindex *if_ni, *i; 43 | int n, cnt = 0; 44 | 45 | if_ni = if_nameindex(); 46 | if (if_ni == NULL) { 47 | perrno_and(return 1, "if_nameindex"); 48 | } 49 | 50 | for (i = if_ni; ! (i->if_index == 0 && i->if_name == NULL); i++, cnt++) { 51 | printf("%u: %s\n", i->if_index, i->if_name); 52 | if (i->if_index == 0) 53 | perr_and(return 1, "if_index = 0, must be greater"); 54 | if (i->if_name == NULL) 55 | perr_and(return 1, "if_name = NULL, must be non-NULL"); 56 | } 57 | 58 | printf("Test 2\n"); 59 | 60 | for (n = 0; n < cnt; n ++) { 61 | int idx = if_nametoindex(if_ni[n].if_name); 62 | if (idx == 0) 63 | perrno_and(return 1, "if_nametoindex"); 64 | if (if_ni[n].if_index != idx) 65 | perr_and(return 1, "if_nametoindex for [%s] is %d instead of %d", if_ni[n].if_name, idx, if_ni[n].if_index); 66 | char buf[IF_NAMESIZE]; 67 | char *name = if_indextoname(if_ni[n].if_index, buf); 68 | if (name == NULL) 69 | perrno_and(return 1, "if_indextoname"); 70 | if (strcmp(if_ni[n].if_name, name) != 0) 71 | perr_and(return 1, "if_indextoname for %d is [%s] instead of [%s]", if_ni[n].if_index, name, if_ni[n].if_name); 72 | } 73 | 74 | if_freenameindex(if_ni); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/poll/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | Version 1.5.1 (2011-08-29) 3 | 4 | * Updated out-of-date license clauses in poll.h and poll.c to be consistent 5 | with the license in the LICENSE file. 6 | 7 | Version 1.5 (2009-08-14) 8 | 9 | * Added nfds_t typedef to poll.h and changed poll() function to use that 10 | type. This change enhances portability for applications that are ported 11 | from systems using newer versions of poll(2). 12 | 13 | * Added instructions (in README) and optional -D parameter (in Makefile) 14 | for working around linkage problems on some Mac OS X systems. 15 | 16 | * Updated license to an OSI-approved BSD license, which is more compatible 17 | with applications using version 3 of the GNU Public License (GPL). 18 | 19 | Thanks to John Gilmore (*gnu@toad.com*) for noting these problems and 20 | suggesting the necessary fixes. 21 | 22 | Version 1.4 (2003-01-01) 23 | 24 | * Now handles and ignores bad file descriptors (i.e., descriptors with 25 | negative values) in poll array. Change is based on a patch submitted by 26 | Dave Smith (*dizzyd@jabber.org*) 27 | 28 | Version 1.3 (2002-09-30) 29 | 30 | * Incorporated changes to Makefile for building on Mac OS/X. (Thanks to 31 | Benjamin Reed (*ranger@befunk.com*) 32 | 33 | Version 1.2 (2002-05-11) 34 | 35 | * Changed WillsCreek.com references to clapper.org. 36 | * Added license info to source code comments 37 | 38 | -------------------------------------------------------------------------------- /src/poll/INSTALL: -------------------------------------------------------------------------------- 1 | BUILDING AND INSTALLING 2 | ----------------------- 3 | 4 | 1) Edit the Makefile, adjusting any necessary definitions. Pay specific 5 | attention to the value of PREFIX and the compiler settings. 6 | 2) Type "make" to build the "libpoll.a" and "libpoll.so" libraries. 7 | 3) Type "make install" to install the shared and static libraries in 8 | $(PREFIX)/lib (default: /usr/local/lib) and the poll.h header file 9 | in $(PREFIX)/include (default: /usr/local/include) 10 | 11 | 12 | USING THE POLL EMULATOR 13 | ----------------------- 14 | 15 | Compiling: 16 | 17 | To compile a program that wants the poll.h header file, you need 18 | to include the appropriate "-I" option on the compiler command line. 19 | If you set PREFIX to "/usr/local", then use "-I/usr/local/include". 20 | For instance: 21 | 22 | cc -c -I/usr/local/include mypollprog.c 23 | 24 | Linking: 25 | 26 | To link a program that uses poll, you need to link against the 27 | static or shared version of the library you built and installed. 28 | Use the "-L" and "-l" options: 29 | 30 | cc -o mypollprog mypollprog.o -L/usr/local/lib -lpoll 31 | 32 | If you need to force static linkage, add "-static" (with gcc) to 33 | force use of "libpoll.a": 34 | 35 | cc -o mypollprog mypollprog.o -L/usr/local/lib -lpoll -static 36 | 37 | POSSIBLE ISSUES 38 | --------------- 39 | 40 | 1. John Gilmore encountered a linking problem on Mac OS X 41 | 10.5 (Leopard). Note that I have not seen this problem on my 10.4 42 | (Tiger) Mac: 43 | 44 | We couldn't merely compile our code and link it with poll.c and have 45 | it work; we got a conflict with the system library: 46 | 47 | /usr/bin/ld: warning multiple definitions of symbol _poll 48 | /var/tmp//ccSgmsaN.o definition of _poll in section (__TEXT,__text) 49 | /usr/lib/gcc/powerpc-apple-darwin8/4.0.0/../../../libSystem.dylib(poll.So) definition of _poll 50 | 51 | Instead we added -Dpoll=myfakepoll when compiling routines that call 52 | poll(), and when compiling poll.c itself, so there'd be no name 53 | conflict. 54 | 55 | If you encounter this problem: 56 | 57 | a) Uncomment the POLL_RENAME definition in the Makefile, rebuild the 58 | poll emulator library, and reinstall it. 59 | b) Be sure to add -Dpoll=pollemu to the C compilation command line for 60 | any program you write that uses the poll emulator. 61 | 62 | --------------------------------------------------------------------------- 63 | -------------------------------------------------------------------------------- /src/poll/LICENSE: -------------------------------------------------------------------------------- 1 | This software is released under the following BSD license, adapted from 2 | http://opensource.org/licenses/bsd-license.php 3 | --------------------------------------------------------------------------- 4 | 5 | Copyright (c) 1995-2011, Brian M. Clapper 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the clapper.org nor the names of its contributors may 19 | be used to endorse or promote products derived from this software without 20 | specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /src/poll/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for poll(2) emulator 2 | # 3 | # $Id$ 4 | # --------------------------------------------------------------------------- 5 | 6 | ############################################################################# 7 | # Definitions that you need to edit 8 | ############################################################################# 9 | 10 | # --------------------------------------------------------------------------- 11 | # Installation prefix 12 | 13 | PREFIX = /usr/local 14 | LIBDIR = $(PREFIX)/lib 15 | INCDIR = $(PREFIX)/include/sys 16 | 17 | # --------------------------------------------------------------------------- 18 | # Platform-specific bits 19 | # 20 | 21 | ######## 22 | # *BSD # 23 | ######## 24 | 25 | # For GNU CC on *BSD. Should work for FreeBSD, NetBSD, OpenBSD and BSD/OS 26 | LINK_SHARED = $(CC) -shared 27 | SHLIB_EXT = so 28 | SHLIB_NOVER = $(LIB_NAME).$(SHLIB_EXT) 29 | SHLIB = $(LIB_NAME).$(SHLIB_EXT).$(VERSION) 30 | SHLIB_INSTALLED = $(LIBDIR)/$(LIB_NAME).$(SHLIB_EXT).$(MAJOR) 31 | 32 | ############ 33 | # Mac OS X # 34 | ############ 35 | 36 | # Benjamin Reed : 37 | # On Mac OS X, comment out the above lines, and uncomment these instead. 38 | #LINK_SHARED = $(CC) -install_name $(PREFIX)/lib/$(SHLIB) \ 39 | # -compatibility_version $(COMPAT_VERSION) \ 40 | # -current_version $(VERSION) -dynamiclib 41 | #SHLIB_EXT = dylib 42 | #SHLIB_NOVER = $(LIB_NAME).$(SHLIB_EXT) 43 | #SHLIB = $(LIB_NAME).$(VERSION).$(SHLIB_EXT) 44 | #SHLIB_INSTALLED= $(LIBDIR)/$(LIB_NAME).$(MAJOR).$(SHLIB_EXT) 45 | 46 | # NOTE: If you have linkage problems on the Mac (see the POSSIBLE ISSUES 47 | # section in the INSTALL file), uncomment the following definition. Be sure 48 | # to use the same -D option when compiling source code that uses this 49 | # library. 50 | 51 | #POLL_RENAME = -Dpoll=pollemu 52 | 53 | # --------------------------------------------------------------------------- 54 | 55 | # If you have a BSD-compatible install(1), use: 56 | INSTALL = install -c 57 | 58 | # If you do not have a BSD-compatible install(1), use: 59 | #INSTALL = ./install.sh -c 60 | 61 | # --------------------------------------------------------------------------- 62 | # Compilation and Linkage 63 | 64 | MAJOR = 1 65 | MINOR = 3 66 | VERSION = $(MAJOR).$(MINOR) 67 | COMPAT_VERSION = $(MAJOR) 68 | CC = cc 69 | LIB_NAME = libpoll 70 | LIB = $(LIB_NAME).a 71 | COMPILE_STATIC = $(CC) -c 72 | COMPILE_SHARED = $(CC) -c -fPIC 73 | RANLIB = ranlib 74 | CPPFLAGS = $(POLL_RENAME) 75 | 76 | ############################################################################# 77 | # There should be no need to edit past this point 78 | ############################################################################# 79 | 80 | .SUFFIXES: .po 81 | 82 | .c.po: 83 | $(COMPILE_SHARED) $(CPP_FLAGS) $< -o $*.po 84 | .c.o: 85 | $(COMPILE_STATIC) $(CPPFLAGS) $< 86 | 87 | all: libs 88 | libs: $(SHLIB) $(LIB) 89 | test: polltest 90 | 91 | dirs: 92 | @echo "creating directories..." 93 | $(INSTALL) -m 755 -d $(LIBDIR) 94 | $(INSTALL) -m 755 -d $(INCDIR) 95 | 96 | install: all dirs 97 | $(INSTALL) -m 755 $(SHLIB) $(LIB) $(LIBDIR) 98 | ln -sf $(SHLIB) $(SHLIB_INSTALLED) 99 | ln -sf $(SHLIB) $(LIBDIR)/$(SHLIB_NOVER) 100 | $(INSTALL) -m 644 poll.h $(INCDIR) 101 | 102 | clean: 103 | rm -f poll.po *.o $(LIB) $(SHLIB) $(SHLIB_NOVER) polltest 104 | 105 | $(SHLIB): poll.po 106 | $(LINK_SHARED) -o $(SHLIB) poll.po 107 | $(LIB): poll.o 108 | ar rv $(LIB) poll.o 109 | polltest: polltest.o 110 | $(CC) -o polltest polltest.o $(LIB) 111 | -------------------------------------------------------------------------------- /src/poll/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This package implements the System V *poll*(2) system call for Unix-like 4 | systems that do not support *poll*. For instance, the following Unix-like 5 | operating systems do not support *poll*: *poll* provides a method for 6 | multiplexing input and output on multiple open file descriptors; in 7 | traditional BSD systems, that capability is provided by *select*(2). While 8 | the semantics of *select* differ from those of *poll*, *poll* can be 9 | readily emulated in terms of *select*, which is exactly what this small 10 | piece of software does. 11 | 12 | Brief documentation on this emulation can be found at the top of the 13 | `poll.h` header file. Also, see the [home page][] for more details. 14 | 15 | [home page]: http://software.clapper.org/poll 16 | 17 | ## Building 18 | 19 | See the [home page][] for details. 20 | 21 | ## License and Copyright 22 | 23 | This software is copyright © 19952010 Brian M. Clapper, and is released 24 | under a BSD license. See the [license][] file for complete details. 25 | 26 | [license]: http://software.clapper.org/poll/license.html 27 | 28 | ## Author 29 | 30 | Brian M. Clapper, [bmc /at/ clapper.org][] 31 | 32 | [bmc /at/ clapper.org]: mailto:bmc@clapper.org 33 | -------------------------------------------------------------------------------- /src/poll/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # install - install a program, script, or datafile 5 | # This comes from X11R5; it is not part of GNU. 6 | # 7 | # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ 8 | # 9 | # This script is compatible with the BSD install script, but was written 10 | # from scratch. 11 | # 12 | 13 | 14 | # set DOITPROG to echo to test this script 15 | 16 | # Don't use :- since 4.3BSD and earlier shells don't like it. 17 | doit="${DOITPROG-}" 18 | 19 | 20 | # put in absolute paths if you don't have them in your path; or use env. vars. 21 | 22 | mvprog="${MVPROG-mv}" 23 | cpprog="${CPPROG-cp}" 24 | chmodprog="${CHMODPROG-chmod}" 25 | chownprog="${CHOWNPROG-chown}" 26 | chgrpprog="${CHGRPPROG-chgrp}" 27 | stripprog="${STRIPPROG-strip}" 28 | rmprog="${RMPROG-rm}" 29 | 30 | instcmd="$mvprog" 31 | chmodcmd="" 32 | chowncmd="" 33 | chgrpcmd="" 34 | stripcmd="" 35 | rmcmd="$rmprog -f" 36 | mvcmd="$mvprog" 37 | src="" 38 | dst="" 39 | 40 | while [ x"$1" != x ]; do 41 | case $1 in 42 | -c) instcmd="$cpprog" 43 | shift 44 | continue;; 45 | 46 | -m) chmodcmd="$chmodprog $2" 47 | shift 48 | shift 49 | continue;; 50 | 51 | -o) chowncmd="$chownprog $2" 52 | shift 53 | shift 54 | continue;; 55 | 56 | -g) chgrpcmd="$chgrpprog $2" 57 | shift 58 | shift 59 | continue;; 60 | 61 | -s) stripcmd="$stripprog" 62 | shift 63 | continue;; 64 | 65 | *) if [ x"$src" = x ] 66 | then 67 | src=$1 68 | else 69 | dst=$1 70 | fi 71 | shift 72 | continue;; 73 | esac 74 | done 75 | 76 | if [ x"$src" = x ] 77 | then 78 | echo "install: no input file specified" 79 | exit 1 80 | fi 81 | 82 | if [ x"$dst" = x ] 83 | then 84 | echo "install: no destination specified" 85 | exit 1 86 | fi 87 | 88 | 89 | # If destination is a directory, append the input filename; if your system 90 | # does not like double slashes in filenames, you may need to add some logic 91 | 92 | if [ -d $dst ] 93 | then 94 | dst="$dst"/`basename $src` 95 | fi 96 | 97 | # Make a temp file name in the proper directory. 98 | 99 | dstdir=`dirname $dst` 100 | dsttmp=$dstdir/#inst.$$# 101 | 102 | # Move or copy the file name to the temp name 103 | 104 | $doit $instcmd $src $dsttmp 105 | 106 | # and set any options; do chmod last to preserve setuid bits 107 | 108 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi 109 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi 110 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi 111 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi 112 | 113 | # Now rename the file to the real destination. 114 | 115 | $doit $rmcmd $dst 116 | $doit $mvcmd $dsttmp $dst 117 | 118 | 119 | exit 0 120 | -------------------------------------------------------------------------------- /src/poll/poll.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*\ 2 | $Id$ 3 | 4 | NAME 5 | 6 | poll - select(2)-based poll() emulation function for BSD systems. 7 | 8 | SYNOPSIS 9 | #include "poll.h" 10 | 11 | struct pollfd 12 | { 13 | int fd; 14 | short events; 15 | short revents; 16 | } 17 | 18 | int poll (struct pollfd *pArray, unsigned long n_fds, int timeout) 19 | 20 | DESCRIPTION 21 | 22 | This file, and the accompanying "poll.c", implement the System V 23 | poll(2) system call for BSD systems (which typically do not provide 24 | poll()). Poll() provides a method for multiplexing input and output 25 | on multiple open file descriptors; in traditional BSD systems, that 26 | capability is provided by select(). While the semantics of select() 27 | differ from those of poll(), poll() can be readily emulated in terms 28 | of select() -- which is how this function is implemented. 29 | 30 | REFERENCES 31 | Stevens, W. Richard. Unix Network Programming. Prentice-Hall, 1990. 32 | 33 | NOTES 34 | 1. This software requires an ANSI C compiler. 35 | 36 | LICENSE 37 | 38 | This software is released under the following BSD license, adapted from 39 | http://opensource.org/licenses/bsd-license.php 40 | 41 | Copyright (c) 1995-2011, Brian M. Clapper 42 | All rights reserved. 43 | 44 | Redistribution and use in source and binary forms, with or without 45 | modification, are permitted provided that the following conditions are met: 46 | 47 | * Redistributions of source code must retain the above copyright notice, 48 | this list of conditions and the following disclaimer. 49 | 50 | * Redistributions in binary form must reproduce the above copyright 51 | notice, this list of conditions and the following disclaimer in the 52 | documentation and/or other materials provided with the distribution. 53 | 54 | * Neither the name of the clapper.org nor the names of its contributors 55 | may be used to endorse or promote products derived from this software 56 | without specific prior written permission. 57 | 58 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 59 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 60 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 62 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 63 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 64 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 65 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 66 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 67 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 68 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 69 | \*---------------------------------------------------------------------------*/ 70 | 71 | #ifndef _POLL_EMUL_H_ 72 | #define _POLL_EMUL_H_ 73 | 74 | #define POLLIN 0x01 75 | #define POLLPRI 0x02 76 | #define POLLOUT 0x04 77 | #define POLLERR 0x08 78 | #define POLLHUP 0x10 79 | #define POLLNVAL 0x20 80 | 81 | #define POLLRDNORM 0x0040 82 | #define POLLRDBAND 0x0080 83 | #define POLLWRNORM 0x0100 84 | #define POLLWRBAND 0x0200 85 | 86 | struct pollfd 87 | { 88 | int fd; 89 | short events; 90 | short revents; 91 | }; 92 | 93 | typedef unsigned long nfds_t; 94 | 95 | #ifdef __cplusplus 96 | extern "C" 97 | { 98 | #endif 99 | 100 | #if (__STDC__ > 0) || defined(__cplusplus) 101 | extern int poll (struct pollfd *pArray, nfds_t n_fds, int timeout); 102 | #else 103 | extern int poll(); 104 | #endif 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | #endif /* _POLL_EMUL_H_ */ 111 | -------------------------------------------------------------------------------- /src/poll/polltest.c: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "poll.h" 8 | 9 | #define MAX 10 10 | 11 | main (int argc, char **argv) 12 | { 13 | int arg; 14 | int i; 15 | struct pollfd array[MAX]; 16 | int ready; 17 | 18 | if ((argc == 1) || ((argc % 2) != 1) || (argc > ((MAX * 2) + 1)) ) 19 | { 20 | fprintf (stderr, "Usage: %s r|w file [r|w file] ...\n", argv[0]); 21 | exit (1); 22 | } 23 | 24 | for (arg = 1, i = 0; arg < argc; arg += 2, i++) 25 | { 26 | int open_mode; 27 | short poll_mask; 28 | char *strMode; 29 | 30 | if (argv[arg][0] == 'r') 31 | { 32 | open_mode = O_RDONLY; 33 | poll_mask = POLLIN; 34 | strMode = "reading"; 35 | } 36 | else 37 | { 38 | open_mode = O_WRONLY; 39 | poll_mask = POLLOUT; 40 | strMode = "writing"; 41 | } 42 | 43 | printf ("%2d: Opening \"%s\" for %s ...\n", i, argv[arg + 1], strMode); 44 | array[i].revents = 0; 45 | array[i].events |= poll_mask; 46 | array[i].fd = open (argv[arg + 1], open_mode); 47 | if (array[i].fd == -1) 48 | { 49 | fprintf (stderr, "Can't open \"%s\": errno %d\n", 50 | argv[arg + 1], errno); 51 | exit (1); 52 | } 53 | } 54 | 55 | printf ("Polling on %d file descriptors. Timeout is indefinite ...\n", i); 56 | ready = poll (array, (unsigned long) i, -1); 57 | printf ("poll() returned %d.\n", ready); 58 | if (ready < 0) 59 | printf ("Errno = %d\n", errno); 60 | 61 | for (arg = 1, i = 0; arg < argc; arg += 2, i++) 62 | { 63 | if (array[i].revents != 0) 64 | { 65 | printf ("%2d (\"%s\"):", i, argv[arg + 1]); 66 | 67 | if (array[i].revents & POLLPRI) 68 | printf (" EXCEPTION"); 69 | if (array[i].revents & POLLIN) 70 | printf (" INPUT"); 71 | if (array[i].revents & POLLOUT) 72 | printf (" OUTPUT"); 73 | putchar ('\n'); 74 | } 75 | } 76 | 77 | exit (0); 78 | } 79 | -------------------------------------------------------------------------------- /src/poll/tst-poll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for poll. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "poll.h" 29 | 30 | static int do_test(void); 31 | #define TEST_FUNCTION do_test() 32 | #include "../test-skeleton.c" 33 | 34 | static int do_test(void) 35 | { 36 | int rc; 37 | int fd; 38 | 39 | fd = create_temp_file("tst-poll-", NULL); 40 | if (fd == -1) 41 | return 1; 42 | 43 | struct pollfd pfd[2]; 44 | 45 | /* 46 | * Test regular files 47 | */ 48 | 49 | pfd[0].fd = fd; 50 | pfd[0].events = POLLIN; 51 | pfd[0].revents = 0; 52 | 53 | rc = poll(pfd, 1, -1); 54 | if (rc == -1) 55 | { 56 | perror("poll regular file for POLLIN failed"); 57 | exit(1); 58 | } 59 | if (rc != 1 || (pfd[0].revents & POLLIN) != POLLIN) 60 | { 61 | printf("poll regular file for POLLIN returned %d and revents %x\n", rc, pfd[0].revents); 62 | exit(1); 63 | } 64 | 65 | pfd[0].events = POLLOUT; 66 | 67 | rc = poll(pfd, 1, -1); 68 | if (rc == -1) 69 | { 70 | perror("poll regular file for POLLOUT failed"); 71 | exit(1); 72 | } 73 | if (rc != 1 || (pfd[0].revents & POLLOUT) != POLLOUT) 74 | { 75 | printf("poll regular file for POLLOUT returned %d revents %x\n", rc, pfd[0].revents); 76 | exit(1); 77 | } 78 | 79 | pfd[0].events = POLLPRI; 80 | 81 | rc = poll(pfd, 1, -1); 82 | if (rc == -1) 83 | { 84 | printf("poll regular file for POLLPRI failed\n"); 85 | exit(1); 86 | } 87 | if (rc != 1 || (pfd[0].revents & POLLPRI) != POLLPRI) 88 | { 89 | printf("poll regular file for POLLPRI returned %d revents %x\n", rc, pfd[0].revents); 90 | exit(1); 91 | } 92 | 93 | /* 94 | * Test sockets 95 | */ 96 | 97 | int p[2]; 98 | 99 | rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, p); 100 | if (rc == -1) 101 | { 102 | perror("socketpair failed"); 103 | return 1; 104 | } 105 | 106 | pid_t pid = fork (); 107 | if (pid == -1) 108 | { 109 | perror("fork failed"); 110 | return 1; 111 | } 112 | 113 | if (pid == 0) 114 | { 115 | /* Child */ 116 | 117 | rc = write(p[1], "Hello", 6); 118 | if (rc == -1) 119 | { 120 | perror("child: write failed"); 121 | exit(1); 122 | } 123 | 124 | sleep(1); 125 | exit(0); 126 | } 127 | 128 | /* Parent */ 129 | 130 | pfd[0].fd = p[0]; 131 | pfd[0].events = POLLIN; 132 | pfd[0].revents = 0; 133 | 134 | rc = poll(pfd, 1, 3000); 135 | if (rc == -1) 136 | { 137 | printf("poll socket for POLLIN failed\n"); 138 | exit(1); 139 | } 140 | if (rc != 1 || (pfd[0].revents & POLLIN) != POLLIN) 141 | { 142 | printf("poll socket for POLLIN returned %d and revents %x\n", rc, pfd[0].revents); 143 | exit(1); 144 | } 145 | else 146 | { 147 | char buf[6] = {0}; 148 | rc = read(p[0], buf, 6); 149 | if (rc != 6 || strncmp(buf, "Hello", 6)) 150 | { 151 | printf("read after select failed or wrong, rc %d, %*.*s\n", 152 | rc, 6, 6, buf); 153 | exit(1); 154 | } 155 | } 156 | 157 | int status; 158 | if (TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) != pid) 159 | { 160 | perror("waitpid failed"); 161 | return 1; 162 | } 163 | 164 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 165 | { 166 | puts("child 1 terminated abnormally or with error"); 167 | return 1; 168 | } 169 | 170 | /* 171 | * Test sockets & files 172 | */ 173 | 174 | pfd[1].fd = fd; 175 | pfd[1].events = POLLPRI; 176 | pfd[1].revents = 0; 177 | 178 | rc = poll(pfd, 2, 3000); 179 | if (rc == -1) 180 | { 181 | printf("poll socket/file for POLLIN/POLLPRI failed\n"); 182 | exit(1); 183 | } 184 | if (rc != 1 || pfd[0].revents || (pfd[1].revents & POLLPRI) != POLLPRI) 185 | { 186 | printf("poll socket for POLLIN returned %d and socket.revents %x file.revents %d\n", 187 | rc, pfd[0].revents, pfd[1].revents); 188 | exit(1); 189 | } 190 | 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/pwrite/tst-pwrite.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2016 bww bitwise works GmbH. 2 | This file is part of the kLIBC Extension Library. 3 | Authored by Dmitry Kuminov , 2016. 4 | 5 | The kLIBC Extension Library is free software; you can redistribute it 6 | and/or modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | The kLIBC Extension Library is distributed in the hope that it will be 11 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with the GNU C Library; if not, see 17 | . */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __OS2__ 30 | #include 31 | #endif 32 | 33 | #define FILE_SIZE 128 34 | 35 | #ifdef DEBUG 36 | #define ITERATIONS 500 37 | #else 38 | #define ITERATIONS 100000 39 | #endif 40 | 41 | char buf[FILE_SIZE]; 42 | 43 | static int do_test(void); 44 | #define TEST_FUNCTION do_test () 45 | #include "../test-skeleton.c" 46 | 47 | static int 48 | do_test (void) 49 | { 50 | int rc; 51 | int i, n; 52 | 53 | int fd = create_temp_file("tst-pwrite-", NULL); 54 | if (fd == -1) 55 | { 56 | puts ("create_temp_file failed"); 57 | return 1; 58 | } 59 | 60 | #ifdef __OS2__ 61 | setmode (fd, O_BINARY); 62 | #endif 63 | 64 | for (i = 0; i < FILE_SIZE; ++i) 65 | buf[i] = i; 66 | 67 | if (TEMP_FAILURE_RETRY ((n = pwrite(fd, buf, FILE_SIZE, 0))) != FILE_SIZE) 68 | { 69 | printf ("write failed (read %d bytes instead of %d)\n", n, FILE_SIZE); 70 | return 1; 71 | } 72 | 73 | struct stat st; 74 | pid_t pid1, pid2; 75 | 76 | printf ("Will do %d iterations of pread/pwrite\n", ITERATIONS); 77 | 78 | if ((pid1 = fork ())) 79 | { 80 | /* parent */ 81 | if ((pid2 = fork ())) 82 | { 83 | /* still parent */ 84 | int rc = 0; 85 | int iter; 86 | for (iter = 0; iter < ITERATIONS; ++iter) 87 | { 88 | if (TEMP_FAILURE_RETRY ((n = pread(fd, buf, FILE_SIZE, 0))) != FILE_SIZE) 89 | { 90 | printf ("pread failed (read %d bytes instead of %d, errno %d)\n", n, FILE_SIZE, errno); 91 | rc = 1; 92 | break; 93 | } 94 | 95 | for (i = 0; i < FILE_SIZE; ++i) 96 | { 97 | if (buf[i] != i) 98 | { 99 | printf ("integrity is broken (offset %d contains %d)\n", i, buf[i]); 100 | rc = 1; 101 | break; 102 | } 103 | } 104 | 105 | if (fstat(fd, &st)) 106 | { 107 | puts ("fstat failed"); 108 | rc = 1; 109 | break; 110 | } 111 | 112 | if ((int)st.st_size != FILE_SIZE) 113 | { 114 | printf ("file size is wrong (%d bytes instead of %d)\n", (int)st.st_size, FILE_SIZE); 115 | rc = 1; 116 | break; 117 | } 118 | } 119 | 120 | if (rc == 1) 121 | { 122 | kill (pid1, SIGKILL); 123 | kill (pid2, SIGKILL); 124 | } 125 | 126 | int status1, status2; 127 | 128 | if (TEMP_FAILURE_RETRY (waitpid (pid1, &status1, 0)) != pid1) 129 | { 130 | perror ("waitpid failed"); 131 | return 1; 132 | } 133 | if (TEMP_FAILURE_RETRY (waitpid (pid2, &status2, 0)) != pid2) 134 | { 135 | perror ("waitpid failed"); 136 | return 1; 137 | } 138 | 139 | if (rc == 0) 140 | rc = status1 || status2; 141 | 142 | return rc; 143 | } 144 | } 145 | 146 | if (pid1 == -1 || pid2 == -1) 147 | { 148 | perror ("fork failed"); 149 | return 1; 150 | } 151 | 152 | /* in child 1 or child 2 */ 153 | printf("Child %d (%d) started\n", getpid(), !!pid1); 154 | 155 | /* child 1 writes to even blocks of 4 bytes, child 2 - to odd block */ 156 | 157 | #if 0 158 | int start = pid1 ? 0 : FILE_SIZE / 2; 159 | int len = FILE_SIZE / 2; 160 | #else 161 | srand (getpid ()); 162 | #endif 163 | 164 | int iter; 165 | for (iter = 0; iter < ITERATIONS; ++iter) 166 | { 167 | int len = 4; 168 | int start = rand () % (FILE_SIZE / (2 * len)); 169 | if (pid1) 170 | start = start * (2 * len); 171 | else 172 | start = start * (2 * len) + len; 173 | for (i = start; i < start + len; ++i) 174 | { 175 | if (TEMP_FAILURE_RETRY (n = pwrite(fd, buf + start, len, start)) != len) 176 | { 177 | printf ("pwrite failed in child %d (wrote %d bytes instead of %d, errno %d)\n", !!pid1, n, len, errno); 178 | return 1; 179 | } 180 | } 181 | } 182 | 183 | printf ("Child %d (%d) ending...\n", getpid(), !!pid1); 184 | 185 | close (fd); 186 | 187 | return 0; 188 | } 189 | -------------------------------------------------------------------------------- /src/select/tst-select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for select. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | static int do_test(void); 29 | #define TEST_FUNCTION do_test() 30 | #include "../test-skeleton.c" 31 | 32 | static int do_test(void) 33 | { 34 | int rc; 35 | int fd; 36 | 37 | fd = create_temp_file("tst-select-", NULL); 38 | if (fd == -1) 39 | return 1; 40 | 41 | fd_set rset; 42 | fd_set wset; 43 | fd_set eset; 44 | struct timeval tm; 45 | 46 | /* 47 | * Test wrong select arguments 48 | */ 49 | tm.tv_sec = 0; 50 | tm.tv_usec = 300000; 51 | rc = select(-1, NULL, NULL, NULL, &tm); 52 | if (rc != -1 && errno != EINVAL) 53 | { 54 | printf("select(-1) returned %d and errno %d instead of -1 and EINVAL\n", rc, errno); 55 | return 1; 56 | } 57 | 58 | /* 59 | * Test select sleep 60 | */ 61 | 62 | rc = select(0, NULL, NULL, NULL, &tm); 63 | if (rc == -1) 64 | { 65 | perror("select sleep failed"); 66 | return 1; 67 | } 68 | 69 | /* 70 | * Test regular files 71 | */ 72 | 73 | FD_ZERO (&rset); 74 | FD_ZERO (&wset); 75 | FD_ZERO (&eset); 76 | 77 | FD_SET(fd, &rset); 78 | 79 | rc = select(fd + 1, &rset, &wset, &eset, NULL); 80 | if (rc == -1) 81 | { 82 | perror("select regular file for reading failed"); 83 | return 1; 84 | } 85 | if (rc != 1 || !FD_ISSET(fd, &rset)) 86 | { 87 | printf("select regular file returned %d and FD_ISSET(reading) %d\n", 88 | rc, !!FD_ISSET(fd, &rset)); 89 | return 1; 90 | } 91 | 92 | FD_ZERO (&rset); 93 | FD_ZERO (&wset); 94 | FD_ZERO (&eset); 95 | 96 | FD_SET(fd, &wset); 97 | 98 | rc = select(fd + 1, &rset, &wset, &eset, NULL); 99 | if (rc == -1) 100 | { 101 | perror("select regular file for writing failed"); 102 | return 1; 103 | } 104 | if (rc != 1 || !FD_ISSET(fd, &wset)) 105 | { 106 | printf("select regular file returned %d and FD_ISSET(writing) %d\n", 107 | rc, !!FD_ISSET(fd, &wset)); 108 | return 1; 109 | } 110 | 111 | FD_ZERO (&rset); 112 | FD_ZERO (&wset); 113 | FD_ZERO (&eset); 114 | 115 | FD_SET(fd, &eset); 116 | 117 | rc = select(fd + 1, &rset, &wset, &eset, NULL); 118 | if (rc == -1) 119 | { 120 | perror("select regular file for exceptions failed"); 121 | return 1; 122 | } 123 | if (rc != 1 || !FD_ISSET(fd, &eset)) 124 | { 125 | printf("select regular file returned %d and FD_ISSET(exceptions) %d\n", 126 | rc, !!FD_ISSET(fd, &eset)); 127 | return 1; 128 | } 129 | 130 | FD_ZERO (&rset); 131 | FD_ZERO (&wset); 132 | FD_ZERO (&eset); 133 | 134 | FD_SET(fd, &rset); 135 | FD_SET(fd, &wset); 136 | 137 | rc = select(fd + 1, &rset, &wset, &eset, NULL); 138 | if (rc == -1) 139 | { 140 | perror("select regular file for reading/writing failed"); 141 | return 1; 142 | } 143 | if (rc != 2 || !FD_ISSET(fd, &rset) || !FD_ISSET(fd, &wset)) 144 | { 145 | printf("select regular file returned %d and FD_ISSET(r) %d FD_ISSET(w) %d\n", 146 | rc, !!FD_ISSET(fd, &rset), !!FD_ISSET(fd, &wset)); 147 | return 1; 148 | } 149 | 150 | /* 151 | * Test sockets 152 | */ 153 | 154 | int p[2]; 155 | 156 | rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, p); 157 | if (rc == -1) 158 | { 159 | perror("socketpair failed"); 160 | return 1; 161 | } 162 | 163 | pid_t pid = fork(); 164 | if (pid == -1) 165 | { 166 | perror("fork failed"); 167 | return 1; 168 | } 169 | 170 | if (pid == 0) 171 | { 172 | /* Child */ 173 | 174 | rc = write(p[1], "Hello", 6); 175 | if (rc == -1) 176 | { 177 | perror("child: write failed"); 178 | exit(1); 179 | } 180 | 181 | exit(0); 182 | } 183 | 184 | /* Parent */ 185 | 186 | FD_ZERO (&rset); 187 | FD_ZERO (&wset); 188 | FD_ZERO (&eset); 189 | 190 | FD_SET (p[0], &rset); 191 | 192 | tm.tv_sec = 3; 193 | tm.tv_usec = 0; 194 | 195 | rc = select(p[0] + 1, &rset, &wset, &eset, &tm); 196 | if (rc == -1) 197 | { 198 | perror("select socket for reading failed"); 199 | return 1; 200 | } 201 | if (rc != 1 || !FD_ISSET(p[0], &rset)) 202 | { 203 | printf("select socket returned %d and FD_ISSET(r) %d\n", 204 | rc, !!FD_ISSET(p[0], &rset)); 205 | return 1; 206 | } 207 | else 208 | { 209 | char buf[6] = {0}; 210 | rc = read(p[0], buf, 6); 211 | if (rc != 6 || strncmp(buf, "Hello", 6)) 212 | { 213 | printf("read after select failed or wrong, rc %d, %*.*s\n", 214 | rc, 6, 6, buf); 215 | exit(1); 216 | } 217 | } 218 | 219 | int status; 220 | if (TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) != pid) 221 | { 222 | perror("waitpid failed"); 223 | return 1; 224 | } 225 | 226 | if (!WIFEXITED(status) || WEXITSTATUS(status)) 227 | { 228 | puts("child 1 terminated abnormally or with error"); 229 | return 1; 230 | } 231 | 232 | /* 233 | * Test sockets & files 234 | */ 235 | 236 | FD_ZERO (&rset); 237 | FD_ZERO (&wset); 238 | FD_ZERO (&eset); 239 | 240 | FD_SET (p[0], &rset); 241 | FD_SET (fd, &eset); 242 | 243 | tm.tv_sec = 3; 244 | tm.tv_usec = 0; 245 | 246 | rc = select(p[0] + 1, &rset, &wset, &eset, &tm); 247 | if (rc == -1) 248 | { 249 | perror("select socket/file for R/E failed"); 250 | return 1; 251 | } 252 | if (rc != 1 || FD_ISSET(p[0], &rset) || !FD_ISSET(fd, &eset)) 253 | { 254 | printf("select socket/file for R/E returned %d and FD_ISSET(socket) %d FD_ISSET(file) %d\n", 255 | rc, !!FD_ISSET(p[0], &rset), !!FD_ISSET(p[0], &eset)); 256 | return 1; 257 | } 258 | 259 | return 0; 260 | } 261 | -------------------------------------------------------------------------------- /src/spawn/spawn2-internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common spawn2 definitions. 3 | * Copyright (C) 2017 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2017. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #define SPAWN2_WRAPPERNAME "libcx-spawn2.wrp" 23 | 24 | typedef struct 25 | { 26 | int mode; 27 | const char *name; 28 | const char *const *argv; 29 | const char *cwd; 30 | const char *const *envp; 31 | const int *stdfds; 32 | 33 | int rc; 34 | int err; 35 | 36 | int _payload_size; 37 | char _payload[0]; 38 | } Spawn2Request; 39 | -------------------------------------------------------------------------------- /src/spawn/spawn2-wrapper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of spawn2 wrapper. 3 | * Copyright (C) 2017 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2017. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #define INCL_BASE 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #define TRACE_GROUP TRACE_GROUP_SPAWN 34 | 35 | #include "../shared.h" 36 | 37 | #include "libcx/spawn2.h" 38 | 39 | #include "spawn2-internal.h" 40 | 41 | int main(int argc, char **argv) 42 | { 43 | TRACE("argc %d argv %p\n", argc, argv); 44 | 45 | int rc = 127; 46 | 47 | if (argc < 3) 48 | TRACE_AND(return rc, "argc %d < 3\n", argc); 49 | 50 | /* 51 | * Note that the semaphore and memory block (which is from LIBCx shared heap) 52 | * are made accessible to this process buy shared_init(). 53 | */ 54 | 55 | APIRET arc; 56 | HEV hev = strtoul(argv[1], NULL, 16); 57 | char *mem = (char *)strtoul(argv[2], NULL, 16); 58 | 59 | /* Copy the data over and report the parent is ok to free it */ 60 | 61 | Spawn2Request *req = (Spawn2Request *)mem; 62 | 63 | /* Force mode to P_WAIT and remove P_2_THREADSAFE + disable inheritance */ 64 | int mode = req->mode; 65 | mode &= ~(P_2_MODE_MASK | P_2_THREADSAFE); 66 | mode |= P_NOWAIT | P_2_NOINHERIT; 67 | 68 | rc = spawn2(mode, req->name, req->argv, req->cwd, req->envp, req->stdfds); 69 | TRACE("spawn2(wrapped child) rc %d (%x) errno %d\n", rc, rc, errno); 70 | 71 | /* Set the spawn result... */ 72 | if (rc == -1) 73 | { 74 | req->rc = -1; 75 | req->err = errno; 76 | } 77 | else 78 | { 79 | req->rc = rc; 80 | } 81 | 82 | /* ...close redirected handles to give the child full control over them... */ 83 | if (req->stdfds) 84 | { 85 | const int *pfd = req->stdfds; 86 | while (*pfd++ != -1) 87 | close(*pfd++); /* close target (child) handle */ 88 | } 89 | 90 | /* ...and report to the parent waiting in spawn2 ASAP */ 91 | arc = DosPostEventSem(hev); 92 | ASSERT_MSG(arc == NO_ERROR || arc == ERROR_ALREADY_POSTED, "%ld %lx", arc, hev); 93 | 94 | if (rc != -1) 95 | { 96 | pid_t pid = rc; 97 | int status; 98 | 99 | rc = waitpid(pid, &status, 0); 100 | TRACE("waitpid(wrapped child) rc %d (%x) status %x errno %d\n", rc, rc, status, errno); 101 | 102 | if (rc != -1) 103 | { 104 | if (WIFEXITED(status)) 105 | rc = WEXITSTATUS(status); 106 | else if (WIFSIGNALED(status)) 107 | raise(WTERMSIG(status)); 108 | else 109 | ASSERT_MSG(0, "invalid status %x", status); 110 | } 111 | } 112 | 113 | return rc; 114 | } 115 | -------------------------------------------------------------------------------- /src/tst-fpucw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for FPU control word recovery. 3 | * Copyright (C) 2018 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2018. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "shared.h" 27 | 28 | static int do_test(void); 29 | #define TEST_FUNCTION do_test() 30 | #include "test-skeleton.c" 31 | 32 | void screw_fpucw() 33 | { 34 | // 0x362 is what some Gpi/Win APIs leave in the FPU CW after themselves. 35 | 36 | __asm__( 37 | "pushl $0x362;" 38 | "fldcw 0(%esp);" 39 | "popl %eax" 40 | ); 41 | } 42 | 43 | static int do_test(void) 44 | { 45 | float a = 1.; 46 | float b = 0.; 47 | 48 | printf("before screw: fpu_cw=%x\n",_control87(0, 0)); 49 | 50 | screw_fpucw(); 51 | 52 | printf("after screw: fpu_cw=%x\n", _control87(0, 0)); 53 | 54 | volatile float c = a / b; 55 | 56 | if (c != INFINITY) 57 | { 58 | printf("c is %f, not %f (fpu_cw=%x)\n", c, INFINITY, _control87(0, 0)); 59 | return 1; 60 | } 61 | 62 | printf("after fix: fpu_cw=%x\n", _control87(0, 0)); 63 | 64 | volatile float c2 = 2. / 0.; 65 | 66 | if (c2 != INFINITY) 67 | { 68 | printf("c2 is %f, not %f (fpu_cw=%x)\n", c2, INFINITY, _control87(0, 0)); 69 | return 1; 70 | } 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/tst-shared.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Testcase for general functionality. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "shared.h" 28 | 29 | static int do_test(void); 30 | #define TEST_FUNCTION do_test() 31 | #include "test-skeleton.c" 32 | 33 | static void check_mem(int nr, size_t hdr_size, size_t expected) 34 | { 35 | int rc; 36 | _HEAPSTATS hst; 37 | 38 | printf("check mem %d\n", nr); 39 | 40 | if (gpData->size != expected) 41 | { 42 | printf("check_mem %d: Committed size is %d, not %d\n", 43 | nr, gpData->size, expected); 44 | exit(1); 45 | } 46 | 47 | rc = _ustats(gpData->heap, &hst); 48 | if (rc) 49 | { 50 | printf("check_mem %d: _ustats failed: %s\n", nr, strerror(errno)); 51 | exit(1); 52 | } 53 | 54 | if (gpData->size - hdr_size != hst._provided) 55 | { 56 | printf("check_mem %d: Total heap size %d mismatches commiited " 57 | "size %d (must be %d)\n", 58 | nr, hst._provided, gpData->size, gpData->size - hdr_size); 59 | exit(1); 60 | } 61 | } 62 | 63 | static int do_test(void) 64 | { 65 | int rc; 66 | _HEAPSTATS hst; 67 | size_t hdr_size; 68 | 69 | global_lock(); 70 | 71 | rc = _ustats(gpData->heap, &hst); 72 | if (rc) 73 | { 74 | perror("_ustats failed"); 75 | return 1; 76 | } 77 | 78 | printf("hst._provided %u\n", hst._provided); 79 | printf("hst._used %u\n", hst._used); 80 | printf("hst._max_free %u\n", hst._max_free); 81 | 82 | if (hst._provided > gpData->size) 83 | { 84 | printf("Total heap size %d is greater than committed size %d\n", 85 | hst._provided, gpData->size); 86 | return 1; 87 | } 88 | 89 | hdr_size = gpData->size - hst._provided; 90 | 91 | printf("hdr_size %u\n", hdr_size); 92 | 93 | check_mem(1, hdr_size, 65536); 94 | 95 | void *data = global_alloc(hst._max_free); 96 | 97 | check_mem(2, hdr_size, 65536); 98 | 99 | void *data2 = global_alloc(5000); 100 | 101 | check_mem(3, hdr_size, 65536 * 2); 102 | 103 | free(data2); 104 | free(data); 105 | 106 | global_unlock(); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Version information. 3 | * Copyright (C) 2016 bww bitwise works GmbH. 4 | * This file is part of the kLIBC Extension Library. 5 | * Authored by Dmitry Kuminov , 2016. 6 | * 7 | * The kLIBC Extension Library is free software; you can redistribute it 8 | * and/or modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * The kLIBC Extension Library is distributed in the hope that it will be 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with the GNU C Library; if not, see 19 | * . 20 | */ 21 | 22 | #ifndef VERSION_H 23 | #define VERSION_H 24 | 25 | /* 26 | * LIBCx version number is defined here. Note that the version number affects 27 | * names of the global shared memory and global mutex. This is in order to 28 | * avoid clashes with older LIBCx versions that might be loaded into memory at 29 | * application runtime and assumes that at least the build number is bumped 30 | * each time there is any change in the binary layout of the global LIBCx 31 | * structures located in shared memory. 32 | */ 33 | #define VERSION_MAJOR 0 34 | #define VERSION_MINOR 7 35 | #define VERSION_BUILD 4 36 | 37 | #define VERSION_MAJ_MIN_TEXTIFY(maj, min) #maj "." #min 38 | #define VERSION_MAJ_MIN_EXPAND(maj, min) VERSION_MAJ_MIN_TEXTIFY(maj, min) 39 | #define VERSION_MAJ_MIN VERSION_MAJ_MIN_EXPAND(VERSION_MAJOR, VERSION_MINOR) 40 | 41 | #define VERSION_MAJ_MIN_BLD_TEXTIFY(maj, min, bld) #maj "." #min "." #bld 42 | #define VERSION_MAJ_MIN_BLD_EXPAND(maj, min, bld) VERSION_MAJ_MIN_BLD_TEXTIFY(maj, min, bld) 43 | #define VERSION_MAJ_MIN_BLD VERSION_MAJ_MIN_BLD_EXPAND(VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD) 44 | 45 | #endif // VERSION_H 46 | --------------------------------------------------------------------------------