#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include #include #define RELOCATABLE 0x1 #define EXECUTABLE 0x2 #define DYNAMIC 0x4 #define CORE 0x8 #define SYMLINKS 0x10 int readline(FILE *f, char *fn); int checkfile(char *fn, unsigned int want, int perr, int quiet); int errors = 0; int zeroterm = 0; int main(int ac, char **av) { int option; unsigned int want = 0; int quiet = 0; int perr = 0; FILE *list = 0; char fn[PATH_MAX]; while ((option = getopt(ac, av, "redclaqp0f:")) != -1) { switch (option) { case 'r': want |= RELOCATABLE; break; case 'e': want |= EXECUTABLE; break; case 'd': want |= DYNAMIC; break; case 'c': want |= CORE; break; case 'l': want |= SYMLINKS; break; case 'a': want = (RELOCATABLE|EXECUTABLE|DYNAMIC|CORE); break; case 'q': quiet++; break; case 'p': perr++; break; case '0': zeroterm = 1; break; case 'f': if (optarg[0] == '-' && optarg[1] == 0) { list = stdin; } else { list = fopen(optarg, "r"); } break; default: exit(1); break; } } if (list) { quiet = 2; perr = 0; while (readline(list, fn)) { fprintf(stderr, "checking %s\n", fn); if (checkfile(fn, want,perr,quiet)) { printf("%s\n", fn); } } } else { fprintf(stderr, "checking %s\n", av[optind]); return !checkfile(av[optind], want,perr,quiet); } return errors ? 1 : 0; } int readline(FILE *f, char *fn) { int ch; int i = 0; do { ch = fgetc(f); switch (ch) { case EOF: break; case 0: if (i == 0) continue; break; case '\n': if (!zeroterm) { if (i == 0) continue; break; } default: fn[i++] = ch; continue; } if (i >= PATH_MAX) { /* TODO print an error */ return 0; } fn[i] = 0; return i; } while (ch != EOF); return 0; } int checkfile(char *fn, unsigned int want, int perr, int quiet) { Elf64_Ehdr hdr; int fd, bytes; int endian = 0; struct stat st; if (want & SYMLINKS) { lstat(fn, &st); } else { stat(fn, &st); } if (!S_ISREG(st.st_mode)) { return 0; } fd = open(fn, O_RDONLY); if (fd == -1) { perror("elfcheck"); errors++; return 0; } bytes = read(fd, &hdr, sizeof hdr); if (bytes < sizeof hdr) { if (perr) fprintf(stderr, "could not read full elf header (wanted %zu got %d bytes)\n", sizeof hdr, bytes); close(fd); return 0; } if (hdr.e_ident[EI_MAG0] != ELFMAG0 || hdr.e_ident[EI_MAG1] != ELFMAG1 || hdr.e_ident[EI_MAG2] != ELFMAG2 || hdr.e_ident[EI_MAG3] != ELFMAG3 ) { if (perr) fprintf(stderr, "elf header magic wrong\n"); close(fd); return 0; } switch (hdr.e_ident[EI_CLASS]) { case ELFCLASS64: case ELFCLASS32: case ELFCLASSNONE: break; default: if (perr) fprintf(stderr, "elf header unknown class\n"); close(fd); return 0; } endian = hdr.e_ident[EI_DATA]; switch (endian) { case ELFDATA2LSB: break; case ELFDATA2MSB: break; /* TODO swap endian if needed */ default: if (perr) fprintf(stderr, "elf header unknown endian\n"); close(fd); return 0; } switch (hdr.e_type) { case ET_REL: if (!quiet) printf("relocatable\n"); close(fd); return want & RELOCATABLE ? 1 : 0; case ET_EXEC: if (!quiet) printf("executable\n"); close(fd); return want & EXECUTABLE ? 1 : 0; case ET_DYN: if (!quiet) printf("dynamic\n"); close(fd); return want & DYNAMIC ? 1 : 0; case ET_CORE: if (!quiet) printf("core\n"); close(fd); return want & CORE ? 1 : 0; case ET_NONE: default: if (perr) fprintf(stderr, "unknown type\n"); close(fd); return 0; } close(fd); return 0; }