#include #include #include #include #include #include #include #include #include #include #include static unsigned int parse_number(const char *text) { char *end; unsigned long value; errno = 0; value = strtoul(text, &end, 0); if (errno != 0 || *end != '\0' || value > UINT_MAX) errx(2, "invalid number: %s", text); return ((unsigned int)value); } int main(int argc, char **argv) { struct stat sb; unsigned int expected_major, expected_minor; bool is_device; if (argc != 3 && argc != 5) errx(2, "usage: stat_special char|block path major minor | " "stat_special fifo path"); if (lstat(argv[2], &sb) != 0) err(1, "lstat %s", argv[2]); is_device = strcmp(argv[1], "char") == 0 || strcmp(argv[1], "block") == 0; if (is_device) { if (argc != 5) errx(2, "device checks require major and minor"); expected_major = parse_number(argv[3]); expected_minor = parse_number(argv[4]); if ((strcmp(argv[1], "char") == 0 && !S_ISCHR(sb.st_mode)) || (strcmp(argv[1], "block") == 0 && !S_ISBLK(sb.st_mode))) errx(1, "%s has the wrong file type", argv[2]); if ((unsigned int)major(sb.st_rdev) != expected_major || (unsigned int)minor(sb.st_rdev) != expected_minor) errx(1, "%s rdev=%#jx major=%u minor=%u, expected %u:%u", argv[2], (uintmax_t)sb.st_rdev, (unsigned int)major(sb.st_rdev), (unsigned int)minor(sb.st_rdev), expected_major, expected_minor); } else if (strcmp(argv[1], "fifo") == 0) { if (argc != 3) errx(2, "FIFO checks do not take major and minor"); if (!S_ISFIFO(sb.st_mode)) errx(1, "%s is not a FIFO", argv[2]); if (sb.st_rdev != NODEV) errx(1, "%s FIFO st_rdev=%#jx, expected NODEV", argv[2], (uintmax_t)sb.st_rdev); } else { errx(2, "unknown type: %s", argv[1]); } printf("PASS path=%s type=%s rdev=%#jx major=%u minor=%u\n", argv[2], argv[1], (uintmax_t)sb.st_rdev, (unsigned int)major(sb.st_rdev), (unsigned int)minor(sb.st_rdev)); return (0); }