DF-3008 / df3008.c
/* DF-3008 - kern.devname race vs clone churn. * thread A: open /dev/ptmx, stat slave, publish rdev, close both (churn) * thread B: sysctl kern.devname on latest published rdev, record results * report: any returned name that is not "pts/N", plus tally */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/sysctl.h> #include <sys/ioctl.h> static volatile dev_t cur = 0; static volatile int stop = 0; static long ok=0, enoent=0, other=0, queries=0; static char weird[1024]; static int weird_n=0; static void *churn(void *a) { struct stat st; while (!stop) { int m = open("/dev/ptmx", O_RDWR); if (m < 0) { usleep(1000); continue; } if (fstat(m, &st) == 0) cur = st.st_rdev; /* cloned master cdev */ close(m); } return NULL; } static void *query(void *a) { char out[256]; size_t len; dev_t d; while (!stop) { d = cur; if (d == 0) continue; len = sizeof(out); memset(out,0,sizeof out); if (sysctlbyname("kern.devname", out, &len, &d, sizeof(d)) == 0) { int n, good=0; if (len>0 && out[len-1]=='\0') len--; if (sscanf(out, "pts/%d", &n)==1) good=1; if (good) ok++; else { other++; if (weird_n < 20) weird_n += snprintf(weird+weird_n, sizeof(weird)-weird_n, "[%s]", out); } } else { if (errno==ENOENT) enoent++; else other++; } queries++; } return NULL; } int main(void) { pthread_t a,b; pthread_create(&a,NULL,churn,NULL); pthread_create(&b,NULL,query,NULL); sleep(20); stop=1; pthread_join(a,NULL); pthread_join(b,NULL); printf("queries=%ld ok_pts=%ld enoent=%ld other=%ld weird=%s\n", queries, ok, enoent, other, weird_n?weird:"-"); return 0; } |