// SPDX-License-Identifier: GPL-2.0-or-later /* rampstream - Generate a check and stream of bytes in a ramp pattern * * Copyright Red Hat * Author: David Gibson */ #include #include #include #include #include #include #include /* Length of the repeating ramp. This is a deliberately not a "round" number so * that we're very likely to misalign with likely block or chunk sizes of the * transport. That means we'll detect gaps in the stream, even if they occur * neatly on block boundaries. Specifically this is the largest 8-bit prime. */ #define RAMPLEN 251 #define INTERVAL 10000 #define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0]))) #define die(...) \ do { \ fprintf(stderr, "rampstream: " __VA_ARGS__); \ exit(1); \ } while (0) static void usage(void) { die("Usage:\n" " rampstream send \n" " Generate a ramp pattern of bytes on stdout, repeated \n" " times\n" " rampstream check \n" " Check a ramp pattern of bytes on stdin, repeater \n" " times\n"); } static void ramp_send(unsigned long long num, const uint8_t *ramp) { unsigned long long i; for (i = 0; i < num; i++) { int off = 0; ssize_t rc; if (i % INTERVAL == 0) fprintf(stderr, "%llu...\r", i); while (off < RAMPLEN) { rc = write(1, ramp + off, RAMPLEN - off); if (rc < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; die("Error writing ramp: %s\n", strerror(errno)); } if (rc == 0) die("Zero length write\n"); off += rc; } } } static void ramp_check(unsigned long long num, const uint8_t *ramp) { unsigned long long i; for (i = 0; i < num; i++) { uint8_t buf[RAMPLEN]; int off = 0; ssize_t rc; if (i % INTERVAL == 0) fprintf(stderr, "%llu...\r", i); while (off < RAMPLEN) { rc = read(0, buf + off, RAMPLEN - off); if (rc < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; die("Error reading ramp: %s\n", strerror(errno)); } if (rc == 0) die("Unexpected EOF, ramp %llu, byte %d\n", i, off); off += rc; } if (memcmp(buf, ramp, sizeof(buf)) != 0) { int j, k; for (j = 0; j < RAMPLEN; j++) if (buf[j] != ramp[j]) break; for (k = j; k < RAMPLEN && k < j + 16; k++) fprintf(stderr, "Byte %d: expected 0x%02x, got 0x%02x\n", k, ramp[k], buf[k]); die("Data mismatch, ramp %llu, byte %d\n", i, j); } } } int main(int argc, char *argv[]) { const char *subcmd = argv[1]; unsigned long long num; uint8_t ramp[RAMPLEN]; char *e; int i; if (argc < 2) usage(); errno = 0; num = strtoull(argv[2], &e, 0); if (*e || errno) usage(); /* Initialize the ramp block */ for (i = 0; i < RAMPLEN; i++) ramp[i] = i; if (strcmp(subcmd, "send") == 0) ramp_send(num, ramp); else if (strcmp(subcmd, "check") == 0) ramp_check(num, ramp); else usage(); exit(0); }