A C program which gets information about itself

This is an example C program which demonstrates a C program running file on itself and parsing the information received.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

static void
check (int test, const char * msg, ...)
{
    if (test) {
	va_list vargs;
	va_start (vargs, msg);
	vfprintf (stderr, msg, vargs);
	va_end (vargs);
	fprintf (stderr, ".\n");
	exit (EXIT_FAILURE);
    }
}

#define BUFSIZE 0x1000

static void
readcommand (FILE * f, char ** results_ptr, int * rlen_ptr)
{
    char buf[BUFSIZE];
    char * results;
    int rlen;
    rlen = 0;
    results = 0;
    while (1) {
	/* Flag to stop the "while" loop. */
	int finished = 0;
	/* How many bytes have been read. */
	int bytes;
	bytes = fread (buf, sizeof (char), BUFSIZE, f);
	if (bytes < BUFSIZE) {
	    check (! feof (f), "fread failed: %s", strerror (errno));
	    finished = 1;
	}
	/* Allocate memory to add bytes + nul terminator. */
	results = realloc (results, rlen + bytes + 1);
	check (! results, "realloc failed");
	memcpy (results + rlen, buf, bytes);
	rlen += bytes;
	/* Nul-terminate string. */
	results[rlen] = '\0';
	if (finished) {
	    * rlen_ptr = rlen;
	    * results_ptr = results;
	    return;
	}
    }
}

typedef enum
{
    unknown,
    no,
    yes
}
binary_data_t;

typedef struct
{
    binary_data_t stripped;
    binary_data_t staticlinked;
}
binary_t;

static void
parsecommand (char * results, int rlen, binary_t * binary)
{
    int offset;
    offset = 0;
    while (1) {
	char * comma;
	int len;
	int finished = 0;
	char * section;
	comma = strchr (results + offset, ',');
	if (comma) {
	    len = comma - results - offset;
	}
	else {
	    finished = 1;
	    len = strlen (results + offset);
	}
	while (isspace (results[offset])) {
	    offset++;
	    len--;
	}
	asprintf (& section, "%.*s\n", len, results + offset);
	if (strstr (section, "stripped")) {
	    if (strstr (section, "not")) {
		binary->stripped = no;
	    }
	    else {
		binary->stripped = yes;
	    }
	}
	if (strstr (section, "linked")) {
	    if (strstr (section, "dynamically")) {
		binary->staticlinked = no;
	    }
	    else if (strstr (section, "static")) {
		binary->staticlinked = yes;
	    }
	    else {
		binary->staticlinked = unknown;
	    }
	}
	free (section);
	if (finished) {
	    return;
	}
	offset += len + 1;
    }
}

static void print_status (const char * what, binary_data_t s)
{
    printf ("%s status: ", what);
    switch (s) {
    case yes:
	printf ("yes");
	break;
    case no:
	printf ("no");
	break;
    case unknown:
	printf ("unknown");
	break;
    }
    printf ("\n");
}

int main (int argc, char ** argv)
{
    char * command;
    FILE * f;
    char * results;
    int rlen;
    binary_t binary = {0};
    asprintf (& command, "file %s", argv[0]);
    check (! command, "asprintf failed: %s", strerror (errno));
    f = popen (command, "r");
    check (! f, "popen failed: %s", strerror (errno));
    readcommand (f, & results, & rlen);
    printf ("%s\n", results);
    parsecommand (results, rlen, & binary);
    print_status ("stripped", binary.stripped);
    print_status ("static", binary.staticlinked);
    free (command);
    free (results);
    pclose (f);
    return 0;
}

(download)

The output of the example looks like this:

./cfi: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), statically linked, for FreeBSD 10.1, not stripped

stripped status: no
static status: yes

Web links


Copyright © Ben Bullock 2009-2017. All rights reserved. For comments, questions, and corrections, please email Ben Bullock (benkasminbullock@gmail.com). / Privacy / Disclaimer