From 28748009c0dc553e2fe5e6253e7615cf89d2b7ef Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:21:13 -0600 Subject: Add clang-format configuration and Makefile rule The settings here are based on the current code style documentation. Signed-off-by: Samuel Holland --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Makefile') diff --git a/Makefile b/Makefile index c595290..6c532fd 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,11 @@ ${LOADER_NAME}: ${LOADER_OBJ} clean: rm -f libgcompat/*.o loader/*.o ${LIBGCOMPAT_NAME} ${LOADER_NAME} +format: + clang-format -i ${LIBGCOMPAT_SRC} ${LOADER_SRC} + install: all install -D -m755 ${LIBGCOMPAT_NAME} ${DESTDIR}/${LIBGCOMPAT_PATH} install -D -m755 ${LOADER_NAME} ${DESTDIR}/${LOADER_PATH} + +.PHONY: all clean format install -- cgit v1.2.3-70-g09d2 From dfafb0735f09d65a392d03a2d1ad3d0b934981da Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:40:59 -0600 Subject: libgcompat: Add and use a macro for defining symbol aliases * Prefer providing the underscore-prefixed symbol as the strong definition. * Do not use a weak alias if the alias is also underscore-prefixed. * Make libgcompat objects depend on the new header. [NOTE: I originally took the weak_alias macro from musl's libc.h, but it's trivial and the same pattern already in use. If desired, I can add the musl copyright notice.] Signed-off-by: Samuel Holland --- Makefile | 4 ++++ libgcompat/alias.h | 9 +++++++++ libgcompat/malloc.c | 14 ++++++-------- libgcompat/math.c | 11 ++++++----- libgcompat/pthread.c | 7 +++---- libgcompat/resolv.c | 13 ++++++------- libgcompat/string.c | 8 ++++---- 7 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 libgcompat/alias.h (limited to 'Makefile') diff --git a/Makefile b/Makefile index 6c532fd..b941dcf 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +LIBGCOMPAT_INCLUDE = \ + libgcompat/alias.h LIBGCOMPAT_SRC = \ libgcompat/backtrace.c \ libgcompat/dlmopen.c \ @@ -33,6 +35,8 @@ ${LIBGCOMPAT_NAME}: ${LIBGCOMPAT_OBJ} $(CC) -o ${LIBGCOMPAT_NAME} -Wl,-soname,${LIBGCOMPAT_NAME} \ -shared ${LIBGCOMPAT_OBJ} +${LIBGCOMPAT_OBJ}: ${LIBGCOMPAT_INCLUDE} + ${LOADER_NAME}: ${LOADER_OBJ} $(CC) -o ${LOADER_NAME} -fPIE -static ${LOADER_OBJ} diff --git a/libgcompat/alias.h b/libgcompat/alias.h new file mode 100644 index 0000000..3f54672 --- /dev/null +++ b/libgcompat/alias.h @@ -0,0 +1,9 @@ +#ifndef _ALIAS_H_ +#define _ALIAS_H_ + +#define alias(old, new) \ + extern __typeof(old) new __attribute__((__alias__(#old))) +#define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((weak, __alias__(#old))) + +#endif /* _ALIAS_H_ */ diff --git a/libgcompat/malloc.c b/libgcompat/malloc.c index db85d8d..dc9d25e 100644 --- a/libgcompat/malloc.c +++ b/libgcompat/malloc.c @@ -27,6 +27,8 @@ #include /* {m,c,re}alloc, free */ #include /* memset */ +#include "alias.h" /* alias */ + struct mallinfo { int arena; /* Non-mmapped space allocated (bytes) */ int ordblks; /* Number of free chunks */ @@ -51,31 +53,27 @@ void *__libc_malloc(size_t size) { return malloc(size); } +alias(__libc_malloc, __malloc); void __libc_free(void *ptr) { return free(ptr); } +alias(__libc_free, __free); void *__libc_calloc(size_t nmemb, size_t size) { return calloc(nmemb, size); } +alias(__libc_calloc, __calloc); void *__libc_realloc(void *ptr, size_t size) { return realloc(ptr, size); } +alias(__libc_realloc, __realloc); void *__libc_memalign(size_t align, size_t len) { return memalign(align, len); } - -extern __typeof(__libc_malloc) __malloc - __attribute__((weak, alias("__libc_malloc"))); -extern __typeof(__libc_calloc) __calloc - __attribute__((weak, alias("__libc_calloc"))); -extern __typeof(__libc_realloc) __realloc - __attribute__((weak, alias("__libc_realloc"))); -extern __typeof(__libc_free) __free __attribute__((weak, alias("__libc_free"))); diff --git a/libgcompat/math.c b/libgcompat/math.c index 42ed032..2982116 100644 --- a/libgcompat/math.c +++ b/libgcompat/math.c @@ -1,26 +1,27 @@ #include /* isinf, isnan */ +#include "alias.h" /* weak_alias */ + int __isinff(float number) { return isinf(number); } +weak_alias(__isinff, isinff); int __isinf(double number) { return isinf(number); } +weak_alias(__isinf, isinf); int __isnanf(float number) { return isnan(number); } +weak_alias(__isnanf, isnanf); int __isnan(double number) { return isnan(number); } - -extern __typeof(__isnanf) isnanf __attribute__((weak, alias("__isnanf"))); -extern __typeof(__isnan) isnan __attribute__((weak, alias("__isnan"))); -extern __typeof(__isinff) isinff __attribute__((weak, alias("__isinff"))); -extern __typeof(__isinf) isinf __attribute__((weak, alias("__isinf"))); +weak_alias(__isnan, isnan); diff --git a/libgcompat/pthread.c b/libgcompat/pthread.c index 52daceb..9333554 100644 --- a/libgcompat/pthread.c +++ b/libgcompat/pthread.c @@ -1,14 +1,13 @@ #include +#include "alias.h" /* weak_alias */ + int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { return pthread_atfork(prepare, parent, child); } - -int register_atfork(void (*prepare)(void), void (*parent)(void), - void (*child)(void)) - __attribute__((weak, alias("__register_atfork"))); +weak_alias(__register_atfork, register_atfork); void __pthread_register_cancel(void *buf) { diff --git a/libgcompat/resolv.c b/libgcompat/resolv.c index 3566dcd..7ad984f 100644 --- a/libgcompat/resolv.c +++ b/libgcompat/resolv.c @@ -9,7 +9,9 @@ #include /* res_state */ #include /* memcpy, memset */ -static inline int res_ninit(res_state statp) +#include "alias.h" /* weak_alias */ + +static inline int __res_ninit(res_state statp) { int rc = res_init(); if (statp != &_res) { @@ -17,8 +19,9 @@ static inline int res_ninit(res_state statp) } return rc; } +weak_alias(__res_ninit, res_ninit); -static inline int res_nclose(res_state statp) +static inline int __res_nclose(res_state statp) { if (!statp) { return -1; @@ -28,8 +31,4 @@ static inline int res_nclose(res_state statp) } return 0; } - -extern __typeof(res_ninit) __res_ninit - __attribute__((weak, alias("res_ninit"))); -extern __typeof(res_nclose) __res_nclose - __attribute__((weak, alias("res_nclose"))); +weak_alias(__res_nclose, res_nclose); diff --git a/libgcompat/string.c b/libgcompat/string.c index 60f61fc..7ca0bf6 100644 --- a/libgcompat/string.c +++ b/libgcompat/string.c @@ -2,6 +2,8 @@ #include /* strto[u?]ll */ #include /* memcpy, strcpy, strncat, strndup */ +#include "alias.h" /* weak_alias */ + /* "Checked" memcpy */ void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) { @@ -60,7 +62,7 @@ char *__strndup(const char *str, size_t count) /* The existance of this method, and the fact it is used in real code, gives * me nightmares. */ -void *rawmemchr(const void *s, int c) +void *__rawmemchr(const void *s, int c) { const unsigned char *haystack = s; unsigned char needle = (unsigned char) c; @@ -68,9 +70,7 @@ void *rawmemchr(const void *s, int c) ; return (void *) haystack; } - -extern __typeof(rawmemchr) __rawmemchr - __attribute__((weak, alias("rawmemchr"))); +weak_alias(__rawmemchr, rawmemchr); /* Another useless __ alias */ char *__strtok_r(char *str, const char *delim, char **saveptr) -- cgit v1.2.3-70-g09d2 From 737aaed25c2a29f00e53b5689ca07108e977cd84 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 19:00:49 -0600 Subject: Makefile: Update compilation options * Remove -DPIC as it is unused (and PIC is always enabled). * Export the loader name as a macro (this will be used in the future). * Enable compiler warnings, except the expected ones. Signed-off-by: Samuel Holland --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index b941dcf..887a7cf 100644 --- a/Makefile +++ b/Makefile @@ -41,9 +41,10 @@ ${LOADER_NAME}: ${LOADER_OBJ} $(CC) -o ${LOADER_NAME} -fPIE -static ${LOADER_OBJ} .c.o: - $(CC) -std=c99 -D_BSD_SOURCE -fPIC -DPIC -DLINKER=\"${LINKER_PATH}\" \ - -DLIBGCOMPAT=\"${LIBGCOMPAT_PATH}\" ${CFLAGS} ${CPPFLAGS} \ - -c -o $@ $< + $(CC) -c -D_BSD_SOURCE -DLIBGCOMPAT=\"${LIBGCOMPAT_PATH}\" \ + -DLINKER=\"${LINKER_PATH}\" -DLOADER=\"${LOADER_NAME}\" \ + -fPIC -std=c99 -Wall -Wextra -Wno-frame-address \ + -Wno-unused-parameter ${CFLAGS} ${CPPFLAGS} -o $@ $< clean: rm -f libgcompat/*.o loader/*.o ${LIBGCOMPAT_NAME} ${LOADER_NAME} -- cgit v1.2.3-70-g09d2 From 51fcab754dabef67a26210a6e1cd752290a10749 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:22:23 -0600 Subject: execinfo: Clean up, implement backtrace_symbols_fd Rename the file to match the header it implements functions from. Changes to existing code: * Fix the return value from backtrace (off by one). * Use __builtin_extract_return_addr as recommended in gcc documentation. * Document header usage. * Document where the functions are referenced in the LSB standard. Signed-off-by: Samuel Holland --- Makefile | 2 +- libgcompat/backtrace.c | 51 -------------------------- libgcompat/execinfo.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 52 deletions(-) delete mode 100644 libgcompat/backtrace.c create mode 100644 libgcompat/execinfo.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 887a7cf..b6ea4f7 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ - libgcompat/backtrace.c \ libgcompat/dlmopen.c \ libgcompat/dlvsym.c \ + libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/malloc.c \ libgcompat/math.c \ diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c deleted file mode 100644 index c8ded8b..0000000 --- a/libgcompat/backtrace.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include - -#define _frame_level(addr_buf, curr, frame, size) \ - do { \ - if (__builtin_frame_address(frame) != NULL \ - && (curr = __builtin_return_address(frame)) > 0x1000 \ - && frame <= size) { \ - addr_buf[frame] = curr; \ - } else { \ - return size; \ - } \ - } while (0) - -int backtrace(void **addr_buf, int size) -{ - void *curr; - _frame_level(addr_buf, curr, 0, size); - _frame_level(addr_buf, curr, 1, size); - _frame_level(addr_buf, curr, 2, size); - _frame_level(addr_buf, curr, 3, size); - _frame_level(addr_buf, curr, 4, size); - _frame_level(addr_buf, curr, 5, size); - _frame_level(addr_buf, curr, 6, size); - _frame_level(addr_buf, curr, 7, size); - _frame_level(addr_buf, curr, 8, size); - _frame_level(addr_buf, curr, 9, size); - return 9; -} - -char **backtrace_symbols(void *const *addr_buf, int size) -{ - char **result = calloc(sizeof(char *), size); - if (result == NULL) { - return result; - } - - for (int next = 0; next < size; next++) { - Dl_info info; - int err = dladdr(addr_buf[next], &info); - - if (err != 0) { - result[next] = "??:0"; - } else { - result[next] = info.dli_sname; - } - } - - return result; -} diff --git a/libgcompat/execinfo.c b/libgcompat/execinfo.c new file mode 100644 index 0000000..59441aa --- /dev/null +++ b/libgcompat/execinfo.c @@ -0,0 +1,97 @@ +#include /* dladdr */ +#include /* NULL */ +#include /* uintptr_t */ +#include /* calloc */ +#include /* strlen */ +#include /* write */ + +#define get_frame_level(array, size, n) \ + do { \ + if (n >= size || __builtin_frame_address(n) == NULL) { \ + return n; \ + } \ + void *address = __builtin_return_address(n); \ + array[n] = __builtin_extract_return_addr(address); \ + if ((uintptr_t) array[n] < 0x1000) { \ + return n; \ + } \ + } while (0) + +/** + * Obtain a backtrace for the calling program. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +int backtrace(void **array, int size) +{ + get_frame_level(array, size, 0); + get_frame_level(array, size, 1); + get_frame_level(array, size, 2); + get_frame_level(array, size, 3); + get_frame_level(array, size, 4); + get_frame_level(array, size, 5); + get_frame_level(array, size, 6); + get_frame_level(array, size, 7); + get_frame_level(array, size, 8); + get_frame_level(array, size, 9); + return 10; +} + +/** + * Translate addresses into symbol information. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +const char **backtrace_symbols(void *const *array, int size) +{ + const char **result = calloc(size, sizeof(char *)); + + if (result == NULL) { + return NULL; + } + for (int i = 0; i < size; ++i) { + Dl_info info; + + if (dladdr(array[i], &info) && info.dli_sname != NULL) { + result[i] = info.dli_sname; + } else { + result[i] = "??:0"; + } + } + + return result; +} + +/** + * Write symbol information to a file without allocating memory. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +void backtrace_symbols_fd(void *const *array, int size, int fd) +{ + for (int i = 0; i < size; ++i) { + Dl_info info; + const char *line; + int len; + + if (dladdr(array[i], &info) && info.dli_sname != NULL) { + line = info.dli_sname; + len = strlen(line); + } else { + line = "??:0"; + len = sizeof("??:0") - 1; + } + while (len > 0) { + int written = write(fd, line, len); + + if (written < 1) { + return; + } + line += written; + len -= written; + } + if (write(fd, "\n", 1) != 1) { + return; + } + } +} -- cgit v1.2.3-70-g09d2 From d0fc6cbef513341ff6b3d12c9b9a1e4093c0a112 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:33:52 -0600 Subject: dlfcn: Combine functions for the same header into one file Changes to existing code: * Make explicit comparison against NULL. * Adjust debug message for readability. Signed-off-by: Samuel Holland --- Makefile | 3 +-- libgcompat/dlfcn.c | 25 +++++++++++++++++++++++++ libgcompat/dlmopen.c | 14 -------------- libgcompat/dlvsym.c | 13 ------------- 4 files changed, 26 insertions(+), 29 deletions(-) create mode 100644 libgcompat/dlfcn.c delete mode 100644 libgcompat/dlmopen.c delete mode 100644 libgcompat/dlvsym.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index b6ea4f7..4873403 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ - libgcompat/dlmopen.c \ - libgcompat/dlvsym.c \ + libgcompat/dlfcn.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/malloc.c \ diff --git a/libgcompat/dlfcn.c b/libgcompat/dlfcn.c new file mode 100644 index 0000000..f2eaa45 --- /dev/null +++ b/libgcompat/dlfcn.c @@ -0,0 +1,25 @@ +#include /* dlopen, dlsym */ +#include /* NULL */ +#include /* fprintf */ +#include /* getenv */ + +void *dlmopen(long lmid, const char *pathname, int mode) +{ + if (getenv("GLIBC_FAKE_DEBUG") != NULL) { + fprintf(stderr, + "loading library %s was requested in namespace %ld", + pathname, lmid); + } + + return dlopen(pathname, mode); +} + +void *dlvsym(void *handle, char *symbol, char *version) +{ + if (getenv("GLIBC_FAKE_DEBUG") != NULL) { + fprintf(stderr, "symbol %s with version %s is being redirected", + symbol, version); + } + + return dlsym(handle, symbol); +} diff --git a/libgcompat/dlmopen.c b/libgcompat/dlmopen.c deleted file mode 100644 index 4584680..0000000 --- a/libgcompat/dlmopen.c +++ /dev/null @@ -1,14 +0,0 @@ -#include /* dlopen */ -#include /* fprintf */ -#include /* getenv */ - -void *dlmopen(long lmid, const char *pathname, int mode) -{ - if (getenv("GLIBC_FAKE_DEBUG")) { - fprintf(stderr, - "library %s was requested to load in %ld namespace", - pathname, lmid); - } - - return dlopen(pathname, mode); -} diff --git a/libgcompat/dlvsym.c b/libgcompat/dlvsym.c deleted file mode 100644 index 0aba245..0000000 --- a/libgcompat/dlvsym.c +++ /dev/null @@ -1,13 +0,0 @@ -#include /* dlsym */ -#include /* fprintf */ -#include /* getenv */ - -void *dlvsym(void *handle, char *symbol, char *version) -{ - if (getenv("GLIBC_FAKE_DEBUG")) { - fprintf(stderr, "symbol %s with version %s is being redirected", - symbol, version); - } - - return dlsym(handle, symbol); -} -- cgit v1.2.3-70-g09d2 From 28096715d49fe420ed194e8520ec5e81bc2cdc85 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:17:13 -0600 Subject: grp: Implement fgetgrent_r/getgrent_r Like fgetpwent_r/getpwent_r, these require a deep copy of the structure into the caller-provided buffer. This is nontrivial for the array of strings member. getgrent_r is required by LSB. [NOTE: I'm not too happy with the macro, but it works. Any suggestions?] Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/grp.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 libgcompat/grp.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 4873403..14c68f4 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ LIBGCOMPAT_SRC = \ libgcompat/dlfcn.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ + libgcompat/grp.c \ libgcompat/malloc.c \ libgcompat/math.c \ libgcompat/pthread.c \ diff --git a/libgcompat/grp.c b/libgcompat/grp.c new file mode 100644 index 0000000..5674fda --- /dev/null +++ b/libgcompat/grp.c @@ -0,0 +1,98 @@ +/* some musl versions incorrectly mark fgetgrent() as a GNU extension */ +#define _GNU_SOURCE +#include /* assert */ +#include /* ENOENT, ERANGE */ +#include /* fgetgrent, getgrent, struct group */ +#include /* pthread_mutex_* */ +#include /* NULL, size_t */ +#include /* ptrdiff_t, uintptr_t */ +#include /* FILE */ +#include /* memcpy, stpcpy, strlcpy, strlen */ + +#define ALIGN_PTR_TO_SIZE_OF(ptr, type) \ + ((type *) ((((uintptr_t)(ptr)) + sizeof(type) - 1) \ + & ~(sizeof(type) - 1))) + +static pthread_mutex_t grent_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int __fgetgrent_r(FILE *stream, struct group *grp, char *buf, size_t len, + struct group **result) +{ + struct group *grtmp; + char *cursor = buf, *end = buf + len; + + *result = NULL; + pthread_mutex_lock(&grent_mutex); + grtmp = stream != NULL ? fgetgrent(stream) : getgrent(); + if (grtmp == NULL) { + pthread_mutex_unlock(&grent_mutex); + return ENOENT; + } + memcpy(grp, grtmp, sizeof(*grp)); + if (grtmp->gr_name != NULL) { + grp->gr_name = cursor; + cursor += strlcpy(cursor, grtmp->gr_name, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (grtmp->gr_passwd != NULL) { + grp->gr_passwd = cursor; + cursor += strlcpy(cursor, grtmp->gr_passwd, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (grtmp->gr_mem != NULL) { + char **members = ALIGN_PTR_TO_SIZE_OF(cursor, char *); + ptrdiff_t nameslen = 0; + size_t nmem = 0; + + /* Calculate total size of strings plus their pointers. */ + while (grtmp->gr_mem[nmem++] != NULL) { + nameslen += strlen(grtmp->gr_mem[nmem - 1]) + 1; + } + nameslen += nmem * sizeof(*members); + if (nameslen > end - ((char *) members)) { + goto err_unlock; + } + /* Copy the pointers, including the NULL sentinel. */ + for (size_t i = 0; i < nmem; ++i) { + members[i] = grtmp->gr_mem[i]; + } + /* Copy the strings (the NULL sentinel doesn't point to one). */ + cursor = (char *) &members[nmem]; + for (size_t i = 0; i < nmem - 1; ++i) { + cursor = stpcpy(cursor, members[i]) + 1; + } + } + pthread_mutex_unlock(&grent_mutex); + *result = grp; + + return 0; + +err_unlock: + pthread_mutex_unlock(&grent_mutex); + return ERANGE; +} + +/** + * Get group file entry. + */ +int fgetgrent_r(FILE *stream, struct group *grp, char *buf, size_t len, + struct group **result) +{ + assert(stream != NULL); + + return __fgetgrent_r(stream, grp, buf, len, result); +} + +/** + * Get group database entry. + * + * LSB 5.0: LSB-Core-generic/baselib-getgrent-r-1.html + */ +int getgrent_r(struct group *grp, char *buf, size_t len, struct group **result) +{ + return __fgetgrent_r(NULL, grp, buf, len, result); +} -- cgit v1.2.3-70-g09d2 From 101dbb13a1d0270b931291607962e6780ec856a5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:39:41 -0600 Subject: stdio: Clean up, add all of LSB stdio plus more * Add all (non-wchar) stdio functions from LSB, plus those found in use in other applications. Document those functions from LSB as such. * Use a consistent structure and paramater names for all functions. * flag == 0 means FORTIFY_SOURCE=1, so the implemented checks should be unconditional. * Add all possible checks without parsing the format string. * Move functions from wchar.h to their own appropriately-named file. Signed-off-by: Samuel Holland --- Makefile | 3 +- libgcompat/stdio.c | 273 +++++++++++++++++++++++++++++++++++++---------------- libgcompat/wchar.c | 40 ++++++++ 3 files changed, 234 insertions(+), 82 deletions(-) create mode 100644 libgcompat/wchar.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 14c68f4..b5fda64 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ LIBGCOMPAT_SRC = \ libgcompat/string.c \ libgcompat/sysctl.c \ libgcompat/ucontext.c \ - libgcompat/version.c + libgcompat/version.c \ + libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} LIBGCOMPAT_SOVERSION = 0 LIBGCOMPAT_NAME = libgcompat.so.${LIBGCOMPAT_SOVERSION} diff --git a/libgcompat/stdio.c b/libgcompat/stdio.c index a44d94c..0ff5feb 100644 --- a/libgcompat/stdio.c +++ b/libgcompat/stdio.c @@ -1,125 +1,236 @@ -#include -#include -#include -#include - -size_t __fread_chk(void *ptr, size_t size, size_t nmemb, FILE *stream) +#define _GNU_SOURCE /* fgets_unlocked */ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* NULL, size_t */ +#include /* feof, fgets, fread, puts, v*printf */ + +int __vasprintf_chk(char **strp, int flag, const char *format, va_list ap); +int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap); +int __vsnprintf_chk(char *s, size_t n, int flag, size_t slen, + const char *format, va_list ap); +int __vsprintf_chk(char *s, int flag, size_t slen, const char *format, + va_list ap); + +/** + * Test end-of-file indicator on a stream. + * + * LSB 5.0: LSB-Core-generic/baselib--io-feof-3.html + */ +int _IO_feof(FILE *stream) { - assert(ptr != NULL); - assert(stream != NULL); - return fread(ptr, size, nmemb, stream); + return feof(stream); } -int __printf_chk(int flag, const char *format, ...) +/** + * Put a string on standard output. + * + * LSB 5.0: LSB-Core-generic/baselib--io-puts-3.html + */ +int _IO_puts(const char *c) { - va_list argp; - int result; + return puts(c); +} - if (flag > 0) { - assert(format != NULL); - } +/** + * Print to allocated string, with stack checking. + */ +int __asprintf_chk(char **strp, int flag, const char *format, ...) +{ + int ret; + va_list ap; - va_start(argp, format); - result = vprintf(format, argp); - va_end(argp); + va_start(ap, format); + ret = __vasprintf_chk(strp, flag, format, ap); + va_end(ap); - return result; + return ret; } -int __fprintf_chk(FILE *stream, int flag, const char *format, ...) +/** + * String input, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fgets-chk-1.html + */ +char *__fgets_chk(char *s, size_t slen, int n, FILE *stream) { - va_list argp; - int result; + assert(s != NULL); + assert(slen >= (size_t) n); + assert(n > 0); + assert(stream != NULL); - if (flag > 0) { - assert(stream != NULL); - assert(format != NULL); - } + return fgets(s, n, stream); +} - va_start(argp, format); - result = vfprintf(stream, format, argp); - va_end(argp); +/** + * Non-locking string input, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fgets-unlocked-chk-1.html + */ +char *__fgets_unlocked_chk(char *s, size_t slen, int n, FILE *stream) +{ + assert(s != NULL); + assert(slen >= (size_t) n); + assert(n > 0); + assert(stream != NULL); - return result; + return fgets_unlocked(s, n, stream); } -int __sprintf_chk(char *str, int flag, size_t strlen, const char *format, ...) +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fprintf-chk-1.html + */ +int __fprintf_chk(FILE *stream, int flag, const char *format, ...) { - va_list argp; - int result; - - assert(strlen > 0); + int ret; + va_list ap; - va_start(argp, format); - result = vsnprintf(str, strlen, format, argp); - va_end(argp); + va_start(ap, format); + ret = __vfprintf_chk(stream, flag, format, ap); + va_end(ap); - return result; + return ret; } -int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, - const char *format, ...) +/** + * Binary input, with stack checking. + */ +size_t __fread_chk(void *buf, size_t buflen, size_t size, size_t nitems, + FILE *stream) { - va_list argp; - int result; + assert(buf != NULL); + assert(size > 0); + assert(buflen / size >= nitems); + assert(stream != NULL); - if (flag > 0) { - assert(format != NULL); - } - // must always be done per LFS - assert(size <= strlen); + return fread(buf, size, nitems, stream); +} - va_start(argp, format); - result = vsnprintf(str, size, format, argp); - va_end(argp); +/** + * Format and print data, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---printf-chk-1.html + */ +int __printf_chk(int flag, const char *format, ...) +{ + int ret; + va_list ap; - return result; + va_start(ap, format); + ret = __vfprintf_chk(stdout, flag, format, ap); + va_end(ap); + + return ret; } -int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, - const wchar_t *format, ...) +/** + * Convert formatted output, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---snprintf-chk-1.html + */ +int __snprintf_chk(char *s, size_t n, int flag, size_t slen, const char *format, + ...) { - va_list argp; - int result; + int ret; + va_list ap; - if (flag > 0) { - assert(format != NULL); - } - // must always be done per LFS - assert(maxlen <= wcslen); + va_start(ap, format); + ret = __vsnprintf_chk(s, n, flag, slen, format, ap); + va_end(ap); - va_start(argp, format); - result = vswprintf(wcs, maxlen, format, argp); - va_end(argp); + return ret; +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---sprintf-chk-1.html + */ +int __sprintf_chk(char *s, int flag, size_t slen, const char *format, ...) +{ + int ret; + va_list ap; - return result; + va_start(ap, format); + ret = __vsprintf_chk(s, flag, slen, format, ap); + va_end(ap); + + return ret; } -int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap) +/** + * Print to allocated string, with stack checking. + */ +int __vasprintf_chk(char **strp, int flag, const char *format, va_list ap) { - if (flag > 0) { - assert(strp != NULL); - assert(fmt != NULL); - } - return vasprintf(strp, fmt, ap); + assert(strp != NULL); + assert(format != NULL); + + return vasprintf(strp, format, ap); } +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vfprintf-chk-1.html + */ int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap) { - if (flag > 0) { - assert(stream != NULL); - assert(format != NULL); - } + assert(stream != NULL); + assert(format != NULL); + return vfprintf(stream, format, ap); } -int __vsnprintf_chk(char *str, size_t size, int flag, size_t strlen, +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vprintf-chk-1.html + */ +int __vprintf_chk(int flag, const char *format, va_list ap) +{ + return __vfprintf_chk(stdout, flag, format, ap); +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsnprintf-chk-1.html + */ +int __vsnprintf_chk(char *s, size_t n, int flag, size_t slen, const char *format, va_list ap) { - if (flag > 0) { - assert(format != NULL); + assert(s != NULL || n == 0); + assert(slen >= n); + assert(format != NULL); + + return vsnprintf(s, n, format, ap); +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsprintf-chk-1.html + */ +int __vsprintf_chk(char *s, int flag, size_t slen, const char *format, + va_list ap) +{ + assert(s != NULL); + assert(slen > 0); + assert(format != NULL); + + return vsprintf(s, format, ap); +} + +/** + * Create a name for a temporary file. + */ +char *tmpnam_r(char *s) +{ + if (s == NULL) { + return NULL; } - // must always be done per LFS - assert(size <= strlen); - return vsnprintf(str, size, format, ap); + + return tmpnam(s); } diff --git a/libgcompat/wchar.c b/libgcompat/wchar.c new file mode 100644 index 0000000..1ddaa1f --- /dev/null +++ b/libgcompat/wchar.c @@ -0,0 +1,40 @@ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* size_t */ +#include /* wchar_t, *wprintf */ + +int __vswprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, va_list ap); + +/** + * Convert formatted wide-character output, with stack checking + * + * LSB 5.0: LSB-Core-generic/baselib---swprintf-chk-1.html + */ +int __swprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, ...) +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = __vswprintf_chk(s, n, flag, slen, format, ap); + va_end(ap); + + return ret; +} + +/** + * Convert formatted wide-character output, with stack checking + * + * LSB 5.0: LSB-Core-generic/baselib---vswprintf-chk-1.html + */ +int __vswprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, va_list ap) +{ + assert(s != NULL || n == 0); + assert(slen >= n); + assert(format != NULL); + + return vswprintf(s, n, format, ap); +} -- cgit v1.2.3-70-g09d2 From b087b07c9649b7e4398093720ebcf96f205c2c49 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:24:00 -0600 Subject: error: Implement the error function This follows the exceptionally-detailed functional description in the manual page. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/error.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 libgcompat/error.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index b5fda64..2ff1495 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ libgcompat/dlfcn.c \ + libgcompat/error.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/grp.c \ diff --git a/libgcompat/error.c b/libgcompat/error.c new file mode 100644 index 0000000..c759b19 --- /dev/null +++ b/libgcompat/error.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE /* program_invocation_name */ +#include /* program_invocation_name */ +#include /* va_list, va_start, va_end */ +#include /* fflush, fputc, fputs, stderr, stdout, vfprintf */ +#include /* strerror */ + +/** + * Print an error message. + * + * LSB 5.0: LSB-Core-generic/baselib-error-n.html + */ +void error(int status, int errnum, const char *format, ...) +{ + va_list ap; + + fflush(stdout); + fputs(program_invocation_name, stderr); + fputs(": ", stderr); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (errnum != 0) { + fputs(": ", stderr); + fputs(strerror(errnum), stderr); + fputc('\n', stderr); + } +} -- cgit v1.2.3-70-g09d2 From 509d6ec7c860e9c327cc9e2860a276787b4bb23f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:27:19 -0600 Subject: misc: Implement some miscellaneous functions Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/misc.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 libgcompat/misc.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 2ff1495..5e6406d 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ LIBGCOMPAT_SRC = \ libgcompat/grp.c \ libgcompat/malloc.c \ libgcompat/math.c \ + libgcompat/misc.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ libgcompat/resolv.c \ diff --git a/libgcompat/misc.c b/libgcompat/misc.c new file mode 100644 index 0000000..aee490f --- /dev/null +++ b/libgcompat/misc.c @@ -0,0 +1,33 @@ +#include /* abort, at_quick_exit */ +#include /* dev_t */ +#include /* major, makedev, minor */ + +/** + * Terminate a function in case of buffer overflow. + * + * LSB 5.0: LSB-Core-generic/baselib---chk-fail-1.html + */ +void __chk_fail(void) +{ + abort(); +} + +int __cxa_at_quick_exit(void (*func)(void), void *__dso_handle) +{ + return at_quick_exit(func); +} + +unsigned int gnu_dev_major(dev_t dev) +{ + return major(dev); +} + +dev_t gnu_dev_makedev(unsigned int maj, unsigned int min) +{ + return makedev(maj, min); +} + +unsigned int gnu_dev_minor(dev_t dev) +{ + return minor(dev); +} -- cgit v1.2.3-70-g09d2 From c13e6ac24f4139a354e068de8472eb6c831a7a23 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:30:25 -0600 Subject: netdb: Add protocol and service functions from LSB These take advantage of the musl implementation for simplicity. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/netdb.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 libgcompat/netdb.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 5e6406d..37c7a70 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ LIBGCOMPAT_SRC = \ libgcompat/malloc.c \ libgcompat/math.c \ libgcompat/misc.c \ + libgcompat/netdb.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ libgcompat/resolv.c \ diff --git a/libgcompat/netdb.c b/libgcompat/netdb.c new file mode 100644 index 0000000..ae7713a --- /dev/null +++ b/libgcompat/netdb.c @@ -0,0 +1,79 @@ +#include /* ENOENT */ +#include /* getproto* */ +#include /* NULL, size_t */ +#include /* memcpy */ + +/** + * Retrieve information from the network protocol database by protocol name, + * reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotobyname-r.html + */ +int getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, + size_t buflen, struct protoent **result) +{ + struct protoent *prototmp = getprotobyname(name); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Retrieve information from the network protocol database by protocol number, + * reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotobynumber-r.html + */ +int getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, + size_t buflen, struct protoent **result) +{ + struct protoent *prototmp = getprotobynumber(proto); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Read the next entry of the protocol database, reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotoent-r.html + */ +int getprotoent_r(struct protoent *result_buf, char *buf, size_t buflen, + struct protoent **result) +{ + struct protoent *prototmp = getprotoent(); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Read the next entry of the network services database, reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getservent-r.html + */ +int getservent_r(struct servent *result_buf, char *buf, size_t buflen, + struct servent **result) +{ + /* musl does not implement getservent(). */ + *result = NULL; + return ENOENT; +} -- cgit v1.2.3-70-g09d2 From 8b7099b1e4ecca1357051142b589eaf24e29051c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:33:24 -0600 Subject: signal: Add a signal function from LSB The other unimplemented signal function in LSB is sigreturn, with is not really implementable. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/signal.c | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 libgcompat/signal.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 37c7a70..e377355 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ LIBGCOMPAT_SRC = \ libgcompat/resolv.c \ libgcompat/resource.c \ libgcompat/setjmp.c \ + libgcompat/signal.c \ libgcompat/stdio.c \ libgcompat/stdlib.c \ libgcompat/string.c \ diff --git a/libgcompat/signal.c b/libgcompat/signal.c new file mode 100644 index 0000000..17e5443 --- /dev/null +++ b/libgcompat/signal.c @@ -0,0 +1,11 @@ +#include /* sigpause */ + +/** + * Remove a signal from the signal mask and suspend the thread. + * + * LSB 5.0: LSB-Core-generic/baselib---xpg-sigpause.html + */ +int __xpg_sigpause(int sig) +{ + return sigpause(sig); +} -- cgit v1.2.3-70-g09d2 From a6ab56ce62bc3c9fa4c63f2f13a3d5f3ea403f19 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:37:33 -0600 Subject: socket: Implement checked socket functions from LSB Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/socket.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 libgcompat/socket.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index e377355..98f87ad 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ LIBGCOMPAT_SRC = \ libgcompat/resource.c \ libgcompat/setjmp.c \ libgcompat/signal.c \ + libgcompat/socket.c \ libgcompat/stdio.c \ libgcompat/stdlib.c \ libgcompat/string.c \ diff --git a/libgcompat/socket.c b/libgcompat/socket.c new file mode 100644 index 0000000..927ebe4 --- /dev/null +++ b/libgcompat/socket.c @@ -0,0 +1,31 @@ +#include /* assert */ +#include /* NULL */ +#include /* recv, recvfrom */ + +/** + * Receive a message from a connected socket, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---recv-chk-1.html + */ +ssize_t __recv_chk(int fd, void *buf, size_t len, size_t buflen, int flags) +{ + assert(buf != NULL); + assert(buflen >= len); + + return recv(fd, buf, len, flags); +} + +/** + * Receive a message from a socket, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---recvfrom-chk-1.html + */ +ssize_t __recvfrom_chk(int fd, void *buf, size_t len, size_t buflen, int flags, + struct sockaddr *address, socklen_t *address_len) +{ + assert(buf != NULL); + assert(buflen >= len); + assert(address != NULL ? address_len != NULL : address_len == NULL); + + return recvfrom(fd, buf, len, flags, address, address_len); +} -- cgit v1.2.3-70-g09d2 From d5183702e36eb43bbb0fa24e31048ca10553d3e9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:39:30 -0600 Subject: syslog: Implement checked syslog functions from LSB Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/syslog.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 libgcompat/syslog.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 98f87ad..dbea5b6 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ LIBGCOMPAT_SRC = \ libgcompat/stdlib.c \ libgcompat/string.c \ libgcompat/sysctl.c \ + libgcompat/syslog.c \ libgcompat/ucontext.c \ libgcompat/version.c \ libgcompat/wchar.c diff --git a/libgcompat/syslog.c b/libgcompat/syslog.c new file mode 100644 index 0000000..5409eba --- /dev/null +++ b/libgcompat/syslog.c @@ -0,0 +1,32 @@ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* NULL */ +#include /* vsyslog */ + +void __vsyslog_chk(int priority, int flag, const char *format, va_list ap); + +/** + * Log a message, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---syslog-chk-1.html + */ +void __syslog_chk(int priority, int flag, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + __vsyslog_chk(priority, flag, format, ap); + va_end(ap); +} + +/** + * Log a message, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsyslog-chk-1.html + */ +void __vsyslog_chk(int priority, int flag, const char *format, va_list ap) +{ + assert(format != NULL); + + vsyslog(priority, format, ap); +} -- cgit v1.2.3-70-g09d2 From 2d70dfb7ae8a3da8015ee9195fa600bf77358764 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:44:27 -0600 Subject: unistd: Implement LSB functions plus more On musl pread and pread64 are the same thing. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/unistd.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 libgcompat/unistd.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index dbea5b6..7996e6b 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ LIBGCOMPAT_SRC = \ libgcompat/sysctl.c \ libgcompat/syslog.c \ libgcompat/ucontext.c \ + libgcompat/unistd.c \ libgcompat/version.c \ libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} diff --git a/libgcompat/unistd.c b/libgcompat/unistd.c new file mode 100644 index 0000000..e19ec8e --- /dev/null +++ b/libgcompat/unistd.c @@ -0,0 +1,172 @@ +#include /* assert */ +#include /* NGROUPS_MAX */ +#include /* NULL, size_t */ +#include /* confstr, getcwd, getgroups, ... */ + +#include "alias.h" /* alias */ + +/** + * Get configurable variables, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---confstr-chk-1.html + */ +size_t __confstr_chk(int name, char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL ? buflen >= len : len == 0); + + return confstr(name, buf, len); +} + +/** + * Get the pathname of the current working directory, with buffer overflow + * checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getcwd-chk-1.html + */ +char *__getcwd_chk(char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= len); + + return getcwd(buf, len); +} + +/** + * Get supplementary group IDs, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getgroups-chk-1.html + */ +int __getgroups_chk(int gidsetsize, gid_t *grouplist, size_t listlen) +{ + assert(grouplist != NULL); + assert(listlen / sizeof(*grouplist) >= (size_t) gidsetsize); + + return getgroups(gidsetsize, grouplist); +} + +/** + * Get name of current host, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---gethostname-chk-1.html + */ +int __gethostname_chk(char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return gethostname(name, namelen); +} + +/** + * Get login name, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getlogin-r-chk-1.html + */ +int __getlogin_r_chk(char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return getlogin_r(name, namelen); +} + +/** + * Get memory page size. + * + * LSB 5.0: LSB-Core-generic/baselib---getpagesize.html + */ +int __getpagesize(void) +{ + return getpagesize(); +} + +/** + * Get the process group ID for a process. + * + * LSB 5.0: LSB-Core-generic/baselib---getpgid-1.html + */ +pid_t __getpgid(pid_t pid) +{ + return getpgid(pid); +} + +/** + * Read from a file, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---pread-chk-1.html + */ +ssize_t __pread_chk(int fd, void *buf, size_t nbytes, off_t offset, + size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= nbytes); + + return pread(fd, buf, nbytes, offset); +} +alias(__pread_chk, __pread64_chk); + +/** + * Read from a file, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---read-chk-1.html + */ +ssize_t __read_chk(int fd, void *buf, size_t nbytes, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= nbytes); + + return read(fd, buf, nbytes); +} + +/** + * Read the contents of a symbolic link, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---readlink-chk-1.html + */ +ssize_t __readlink_chk(const char *path, char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= len); + + return readlink(path, buf, len); +} + +/** + * Get configurable system variables. + * + * LSB 5.0: LSB-Core-generic/baselib---sysconf.html + */ +long __sysconf(int name) +{ + return sysconf(name); +} + +/** + * Find the pathname of a terminal, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---ttyname-r-chk-1.html + */ +int __ttyname_r_chk(int fd, char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return ttyname_r(fd, name, namelen); +} + +/** + * Test whether a process is in a group. + */ +int group_member(gid_t gid) +{ + gid_t groups[NGROUPS_MAX]; + int ngroups = getgroups(NGROUPS_MAX, groups); + + for (int i = 0; i < ngroups; ++i) { + if (groups[i] == gid) { + return 1; + } + } + + return 0; +} -- cgit v1.2.3-70-g09d2 From bf7102a303ec86f2d9bc9fd451db78a6815ca175 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:46:06 -0600 Subject: utmp: Implement the reentrant utmp function from LSB This takes advantage of the (lack of a) musl implementation for simplicity. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/utmp.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 libgcompat/utmp.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 7996e6b..5e5a12e 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ LIBGCOMPAT_SRC = \ libgcompat/syslog.c \ libgcompat/ucontext.c \ libgcompat/unistd.c \ + libgcompat/utmp.c \ libgcompat/version.c \ libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} diff --git a/libgcompat/utmp.c b/libgcompat/utmp.c new file mode 100644 index 0000000..c2bdd91 --- /dev/null +++ b/libgcompat/utmp.c @@ -0,0 +1,14 @@ +#include /* NULL */ +#include /* struct utmp */ + +/** + * Get user accounting database entries. + * + * LSB 5.0: LSB-Core-generic/baselib-getutent-r-3.html + */ +int getutent_r(struct utmp *buffer, struct utmp **result) +{ + /* musl does not implement getutent(). */ + *result = NULL; + return -1; +} -- cgit v1.2.3-70-g09d2 From 6d391f9ef2d2588ae2faf0efb73bd1ac934b063a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:54:49 -0600 Subject: readlink: Intercept readlink("/proc/self/exe") This allows programs run through gcompat to fork and re-exec themselves. It fixes readlink("/proc/self/exe") to return the executable's absolute path, instead of musl's path. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/readlink.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 libgcompat/readlink.c (limited to 'Makefile') diff --git a/Makefile b/Makefile index 5e5a12e..b6bee29 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ LIBGCOMPAT_SRC = \ libgcompat/netdb.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ + libgcompat/readlink.c \ libgcompat/resolv.c \ libgcompat/resource.c \ libgcompat/setjmp.c \ diff --git a/libgcompat/readlink.c b/libgcompat/readlink.c new file mode 100644 index 0000000..63def96 --- /dev/null +++ b/libgcompat/readlink.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef LINKER +#error LINKER must be defined +#endif + +static char exe[PATH_MAX], *linker; +static ssize_t (*real_readlink)(const char *, char *, size_t); + +ssize_t readlink(const char *path, char *buf, size_t len) +{ + if (real_readlink == NULL) { + real_readlink = dlsym(RTLD_NEXT, "readlink"); + if (real_readlink == NULL) { + return -1; + } + } + + if (!strcmp(path, "/proc/self/exe")) { + int fd; + + if (exe[0] == '\0') { + if (linker == NULL) { + linker = realpath(LINKER, NULL); + if (linker == NULL) { + return -1; + } + } + if (real_readlink(path, exe, sizeof(exe)) < 1) { + goto fail; + } + if (!strcmp(exe, linker)) { + char c; + int arg = 0; + ssize_t arglen; + + fd = open("/proc/self/cmdline", + O_RDONLY | O_CLOEXEC); + if (fd < 0) { + goto fail; + } + /* Skip the --argv0/--preload ldso args. + * This number must be kept in sync with the + * argument order in loader/loader.c */ + while (arg < 5) { + if (read(fd, &c, 1) != 1) { + goto fail_close; + } + if (c == '\0') { + ++arg; + } + } + /* Read the executable path from the cmdline. */ + arglen = read(fd, exe, sizeof(exe)); + if (arglen < 1) { + goto fail_close; + } + close(fd); + /* Ensure the path exists, fits, and has NUL. */ + if (exe[0] == '\0') { + goto fail; + } + if (strnlen(exe, arglen) == (size_t) arglen) { + goto fail; + } + } + } + + return stpncpy(buf, exe, len) - buf; + + fail_close: + close(fd); + fail: + exe[0] = '\0'; + return -1; + } + + return real_readlink(path, buf, len); +} -- cgit v1.2.3-70-g09d2