How My Audit Process Works

During the build process for the kernel, a program just scans code for markings “NEW CODE” or “OLD CODE” in each file and prints a report. Obviously this simple method can be adapted to check for more complicated audit requirements e.g. checking that each file has been reviewed within a certain timeframe (the current process just checks which files have been written anew versus which are old code).

Totals are rounded so will usually add up to just under 100%. This is only a simple tool and can be extended later for more thorough audit statistics!

But this is a really powerful tool. You ever written an OS kernel? I’ve written most of one, but I did it the easy way: One piece at a time.

// Copyright (c) 2025, Rainbow (Zak) Yani Star Fenton
// This "audit" program is licensed under the Mulan PSL v2. You can use this
// software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
// any kind, either express or implied, including but not limited to
// non-infringement, merchantability or fit for a particular purpose.
// See the Mulan PSL v2 for more details.

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>

#define AUDIT_TYPE_OLD      1
#define AUDIT_TYPE_NEW      2
#define AUDIT_TYPE_UNMARKED 3

typedef struct audit_info audit_info_t;
typedef struct audit_filelist audit_filelist_t;
struct audit_filelist {
  const char* name;
  audit_filelist_t* next;
  int type;
  int lines;
};
struct audit_info {
  int filecount;
  int linecount;
  audit_filelist_t* oldcode;
  audit_filelist_t* newcode;
  audit_filelist_t* unmarkedcode;
};

int audit_filelist_countfiles(audit_filelist_t* l) {
  int total = 0;
  while (l) {
    total++;
    l = l->next;
  }
  return total;
}

int audit_filelist_countlines(audit_filelist_t* l) {
  int total = 0;
  while (l) {
    total += l->lines;
    l = l->next;
  }
  return total;
}

int usage(int argc, char** argv, const char* error) {
  FILE* out = error ? stderr : stdout;
  fprintf(out, "ABOUT:\n");
  fprintf(out, "This is a simple code audit tool to note occurrences like OLD CODE & NEW CODE\n");
  fprintf(out, "The main purpose of this tool is to help gradually remove old/third-party code from a codebase,\n");
  fprintf(out, "but it could be extended later e.g. for checking each file has been manually audited at a recent date.\n");
  fprintf(out, "This tool isn't specific to a particular programming language and can be used for config files too.\n");
  fprintf(out, "\nUSAGE:\n");
  fprintf(out, "\t%s [source files...]\n", argv[0]);
  if (error) {
    fprintf(out, "ERROR: %s\n", error);
    return -1;
  } else {
    return 0;
  }
}

int audit_check(const char* line, const char* check) {
  char c;
  while ((c = *line++) != 0) {
    if (c == check[0]) {
      const char* search = check+1;
      while (*search && *search == *line) {
        line++;
        search++;
      }
      if (!*search) {
        return 1; // Found!
      }
    }
  }
  return 0; // Not found
}

void audit_line(audit_info_t* info, audit_filelist_t* file, const char* line) {
  if (audit_check(line, "OLD CODE")) {
    file->type = AUDIT_TYPE_OLD;
  } else if (file->type == AUDIT_TYPE_UNMARKED && audit_check(line, "NEW CODE")) {
    file->type = AUDIT_TYPE_NEW;
  }
  file->lines++;
}

char linebuf[1000];

int audit_run(audit_info_t* info, const char* filename) {
  FILE* f = fopen(filename, "r");
  if (!f) {
    return -1;
  }
  audit_filelist_t* filelist = malloc(sizeof(audit_filelist_t));
  if (!filelist) {
    fprintf(stderr, "ERROR: Failed to allocate memory\n");
    fclose(f);
    return -1;
  }
  filelist->name = strdup(filename);
  filelist->type = AUDIT_TYPE_UNMARKED;
  filelist->lines = 0;
  filelist->next = NULL;
  
  while (fgets(linebuf, 1000, f)) {
    audit_line(info, filelist, linebuf);
  }
  
  switch (filelist->type) {
    case AUDIT_TYPE_NEW:
      filelist->next = info->newcode;
      info->newcode = filelist;
      break;
    case AUDIT_TYPE_OLD:
      filelist->next = info->oldcode;
      info->oldcode = filelist;
      break;
    default:
      filelist->next = info->unmarkedcode;
      info->unmarkedcode = filelist;
      break;
  }
  info->linecount += filelist->lines;
  
  fclose(f);
  return 0;
}

void audit_subreport(audit_info_t* info, const char* startline, audit_filelist_t* files, FILE* out, int extrastats) {
  int nfiles = audit_filelist_countfiles(files);
  int nlines = audit_filelist_countlines(files);
  int fpercent = (int) (((double) nfiles) / ((double) (info->filecount)) * 100);
  int lpercent = (int) (((double) nlines) / ((double) (info->linecount)) * 100);
  fprintf(out, "%s %d FILES (%d%%)\t%d LINES (%d%%)\n", startline, nfiles, fpercent, nlines, lpercent);
  if (!files) {
    return;
  }
  //fprintf(out, "%s IN ", startline);
  audit_filelist_t* smallest = files;
  audit_filelist_t* largest = files;
  while (files) {
    //fprintf(out, " %s", files->name);
    if (files->lines < smallest->lines) {
      smallest = files;
    } else if (files->lines > largest->lines) {
      largest = files;
    }
    files = files->next;
  }
  //fprintf(out, "\n");
  if (extrastats) {
    fprintf(out, "%s SMALLEST %s (%d lines) LARGEST %s (%d lines)\n", startline, smallest->name, smallest->lines, largest->name, largest->lines);
  }
}

void audit_report(audit_info_t* info, FILE* out) {
  fprintf(out, "THIS IS AN AUTOGENERATED REPORT\n");
  fprintf(out, "This report was created by the 'audit' program\n");
  fprintf(out, "TOTAL %d FILES %d LINES\n", info->filecount, info->linecount);
  audit_subreport(info, "NEW CODE:     ", info->newcode, out, 0);
  audit_subreport(info, "OLD CODE:     ", info->oldcode, out, 1);
  audit_subreport(info, "UNMARKED CODE:", info->unmarkedcode, out, 1);
}

int main(int argc, char** argv) {
  audit_info_t info;
  info.filecount = 0;
  info.oldcode = NULL;
  info.newcode = NULL;
  info.unmarkedcode = NULL;
  
  for (int i = 1; i < argc; i++) {
    if (audit_run(&info, argv[i]) != 0) {
      fprintf(stderr, "ERROR: Failed to process file '%s'\n", argv[i]);
      return -1;
    }
    info.filecount++;
  }
  
  if (info.filecount < 1) {
    return usage(argc, argv, "Expecting list of source files\n");
  } else {
    audit_report(&info, stdout);
    return 0;
  }
}

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *