/*
 * glibc_shim.c
 * Provides glibc-specific symbols that uClibc does not export,
 * so the binary can run on a uClibc-based device.
 */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char **environ;

/*
 * __libc_start_main — called by glibc's crt1.o _start before main().
 * uClibc provides this too, but versioned symbol mismatches prevent
 * resolution at runtime. Define it here so the PLT binds locally.
 */
int __libc_start_main(
    int (*main)(int, char **, char **),
    int argc, char **argv,
    void (*init)(int, char **, char **),   /* __libc_csu_init takes 3 args */
    void (*fini)(void),
    void (*rtld_fini)(void),
    void *stack_end)
{
    /* environ sits just after the NULL terminator of argv */
    environ = argv + argc + 1;

    /* Skip init (__libc_csu_init / frame_dummy) — glibc .init_array
     * registration crashes under ld-uClibc. Shared-library constructors
     * are handled by ld-uClibc via DT_INIT/DT_INIT_ARRAY in each .so. */
    int ret = main(argc, argv, environ);
    if (fini) fini();
    exit(ret);
}

/* Fortified printf variants — emitted by -D_FORTIFY_SOURCE=2 */
int __printf_chk(int flag, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int ret = vprintf(fmt, ap);
    va_end(ap);
    return ret;
}

int __fprintf_chk(FILE *fp, int flag, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int ret = vfprintf(fp, fmt, ap);
    va_end(ap);
    return ret;
}

int __snprintf_chk(char *s, size_t maxlen, int flag,
                   size_t slen, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int ret = vsnprintf(s, maxlen, fmt, ap);
    va_end(ap);
    return ret;
}

int __sprintf_chk(char *s, int flag, size_t slen, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int ret = vsprintf(s, fmt, ap);
    va_end(ap);
    return ret;
}

int __vsnprintf_chk(char *s, size_t maxlen, int flag,
                    size_t slen, const char *fmt, va_list ap)
{
    return vsnprintf(s, maxlen, fmt, ap);
}

/* Fortified memory/string variants */
void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen)
{
    return memcpy(dest, src, len);
}

void *__memset_chk(void *s, int c, size_t len, size_t destlen)
{
    return memset(s, c, len);
}

char *__strcpy_chk(char *dest, const char *src, size_t destlen)
{
    return strcpy(dest, src);
}

char *__strcat_chk(char *dest, const char *src, size_t destlen)
{
    return strcat(dest, src);
}
