--- /dev/null
+#define _POSIX_C_SOURCE 200112L
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#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 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;
+}