#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include #include "elf.h" #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 errors = 0; int zeroterm = 0; int main(int ac, char **av) { int option; unsigned int want = 0; int printtype = 0; int printname = 0; int verbose = 0; int perr = 0; FILE *list = 0; char fn[PATH_MAX]; while ((option = getopt(ac, av, "vtnredclap0f:")) != -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 't': printtype++; break; case 'n': printname++; break; case 'v': verbose++; 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 (!want) want = (RELOCATABLE|EXECUTABLE|DYNAMIC|CORE); if (list) { int type; perr = 0; while (readline(list, fn)) { if ((type = checkfile(fn, want, perr)) & want) { if (printtype) { switch (type) { case RELOCATABLE: printf("relocatable "); break; case EXECUTABLE: printf("executable "); break; case DYNAMIC: printf("dynamic "); break; case CORE: printf("core "); break; default: printf("notelf "); break; } } printf("%s\n", fn); } } } else { int type; char *fn; fn = av[optind]; if (verbose) fprintf(stderr, "checking %s\n", av[optind]); type = checkfile(fn,want,perr); if (printtype) { switch (type) { case RELOCATABLE: printf("relocatable"); break; case EXECUTABLE: printf("executable"); break; case DYNAMIC: printf("dynamic"); break; case CORE: printf("core"); break; default: printf("notelf"); break; } } if (printname) { printf("%s%s", printtype ? " " : "", fn); } if (printtype || printname) printf("\n"); return type & want ? 0 : 1; } 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) { 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); close(fd); if ((size_t)bytes < sizeof hdr) { if (perr) fprintf(stderr, "could not read full elf header (wanted %zu got %d bytes)\n", sizeof hdr, bytes); 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"); 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"); 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"); return 0; } switch (hdr.e_type) { case ET_REL: return RELOCATABLE; case ET_EXEC: return EXECUTABLE; case ET_DYN: return DYNAMIC; case ET_CORE: return CORE; case ET_NONE: default: if (perr) fprintf(stderr, "unknown %s\n", fn); return 0; } return 0; }