#include <stdbool.h>
#include <sys/resource.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <argp.h>

#include <sys/auxv.h>

/* workarround bug on arm see #1086502*/
#ifdef __arm__
#ifndef HWCAP_CRC32
#include <asm/hwcap.h>
#endif
#endif

#if defined(__x86_64__) || defined(__i386__)
#include <sys/platform/x86.h>
#endif

const char *argp_program_version = "test-ARMv6 version 27";
static char doc[] = "return success if ARMv6\n"
 "\n"
 "The ARMv6 architecture (not to be confused with product family ARM6) uses\n"
 "physically addressed cache, solving many cache aliasing problems and\n"
 "reducing context switch overhead. Unaligned and mixed-endian data access is\n"
 "supported. This architecture includes the first version of Thumb\n"
 "technology.\n"
 "\n"
 "This feature is not guaranteed by the architecture baseline, but is\n"
 "available for newer armel machines in the ARM11 product family, including\n"
 "ARM1136J(F)-S, ARM1156T2(F)-S, ARM1176JZ(F)-S, ARM1136EJ(F)-S, and\n"
 "ARM11MPCore processors. Boards include the Raspberry Pi model 1 and\n"
 "Raspberry Pi Zero.";
static struct argp argp = { 0, 0, 0, doc };

#ifdef AT_PLATFORM
/* detect ARM ABI version will be optimized away if not used */
static inline bool need_armv_version(int atleastversion)
{
    int version;
    const char * platform = (const char *)getauxval(AT_PLATFORM);
    if (platform == NULL)
        return false;
    /* at least v5 */
    if (strlen(platform) < strlen("v5"))
        return false;
    if (*(platform++) != 'v')
        return false;

    char *endstr;
    errno = 0;
    version = strtol(platform,&endstr,10);
    if (errno != 0)
        return false;
    if (endstr == platform)
        return false;

    return (version >= atleastversion);

}
#endif

const struct rlimit nocore = { 0, 0 };

/* emulate kill by signal */
void
termination_handler (int signum)
{
    _exit(128+signum);
}

int main(int argc,char **argv)
{
    /* no core */
    (void) setrlimit(RLIMIT_CORE, &nocore);
    /* return instead */
    struct sigaction new_action;
    new_action.sa_handler = termination_handler;
    (void) sigemptyset (&new_action.sa_mask);
    new_action.sa_flags = 0;
    (void) sigaction (SIGILL, &new_action, NULL);
    (void) sigaction (SIGBUS, &new_action, NULL);
    (void) sigaction (SIGSEGV, &new_action, NULL);
    argp_parse (&argp, argc, argv, 0, 0, 0);
    /* now test */
    return !need_armv_version(6);;
    return 0;
}
