// stat/fstat/isatty regression for the GNO libc file-status surface.
//
// Exercises the three K* status primitives (Kstat/Kfstat 0x2703/0x2803)
// through their POSIX wrappers in libcGno.c, plus isatty() built on
// fstat.  The hard part these wrappers get right is struct stat's
// byte-layout: the GNO kernel (kern/gno/stat.c, ORCA/C) writes the buffer
// directly, so if runtime/include/sys/stat.h drifts by even one field the
// S_IF* type bits land in the wrong word and every test below flips.
//
// The program is launched at the gsh prompt with stdout on the console
// TTY, so:
//   - fstat(1) succeeds and st_mode is a character special (the TTY).
//   - isatty(1) is therefore true.
//   - stat(".") on the login cwd is a directory.
// All deterministic (no pids / addresses / times inspected).
//
// Bank-2 absolute uint16 markers (DBR-independent), per the gnoHeapProbe
// convention:
//   0x025000  C0DE  reached end (no hang in any stat path)
//   0x025010  0001  fstat(1) returned 0
//   0x025012  0001  S_ISCHR(fstat st_mode) -- stdout is a char device
//   0x025014  0001  isatty(1) == 1
//   0x025016  0001  stat(".") returned 0
//   0x025018  0001  S_ISDIR(stat st_mode) -- cwd is a directory
#include <stdint.h>
#include <sys/stat.h>

extern int isatty(int fd);

#define M(a) (*(volatile uint16_t *)(a))
#define OK   0x0001
#define BAD  0xDEAD


int main(void) {
    struct stat sb;
    int         rc;

    M(0x025010UL) = BAD;
    M(0x025012UL) = BAD;
    M(0x025014UL) = BAD;
    M(0x025016UL) = BAD;
    M(0x025018UL) = BAD;

    // fstat(1): stdout, which the harness leaves on the console TTY.
    rc = fstat(1, &sb);
    if (rc == 0) {
        M(0x025010UL) = OK;
    }
    if (S_ISCHR(sb.st_mode)) {
        M(0x025012UL) = OK;
    }

    // isatty(1): true because stdout is a character device.
    if (isatty(1) == 1) {
        M(0x025014UL) = OK;
    }

    // stat("."): the login cwd, which is a directory.
    rc = stat(".", &sb);
    if (rc == 0) {
        M(0x025016UL) = OK;
    }
    if (S_ISDIR(sb.st_mode)) {
        M(0x025018UL) = OK;
    }

    M(0x025000UL) = 0xC0DE;                  // reached end
    for (volatile unsigned long j = 0; j < 600000UL; j++) {
    }
    return 0;
}
