Logo Search packages:      
Sourcecode: lanmap version File versions  Download package

os_classify.c

/* ex: set tabstop=4 noet: */
/**
 * organize operating systems into a family tree; allow us to apply very
 * specific as well as very general "hints"
 * TODO: build a .dot file representing OS tree to aid in human visualization of os tree
 */

#include <stdio.h>
#include <stdlib.h> /* exit, qsort */
#include <string.h> /* memset */
#include <assert.h>
#include "misc.h" /* strlcpy, strlcat */
#ifdef WIN32
      #include <sys/types.h>
#endif

#include "os_classify.h"

#define OS_GRAPH_FILE   "graph/os_ref.dot"

/**
 * manually organized node in the OS family tree
 */
typedef struct _os_config os_config;
struct _os_config {
      int id;
      int family; /* family name to reference when generating description */
      char name_short[32];
      time_t release; /*  */
      int child_count;
      int child[OS_TREE_MAXCHILD];
};

/**
 * define operating system human-readable names and relationships
 * NOTE: must be synced with OS_* enum in classify.h, entries must match up
 */
static os_config OS_Config[] = {
      /*id                    family                  name_short        release     chcntchild */
      { OS_UNKNOWN,           OS_UNKNOWN,       "?",              0,          0,    { OS_NONE } },
      { OS_UNIX,              OS_UNIX,          "*NIX",                 0,          2,    { OS_BSD, OS_LINUX } },
      /* BSD */
      { OS_BSD,               OS_BSD,                 "BSD",                  0,          2,    { OS_FREEBSD, OS_NETBSD } },
      { OS_NETBSD,            OS_NETBSD,        "NetBSD",         0,          1,    { OS_NETBSD_1X } },
      { OS_NETBSD_1X,         OS_NETBSD,        "1.x",                  0,          2,    { OS_NETBSD_13, OS_OPENBSD } },
      { OS_NETBSD_13,         OS_NETBSD,        "1.3",                  0,          1,    { OS_NETBSD_2X } },
      { OS_NETBSD_2X,         OS_NETBSD,        "2.x",                  0,          0,    { OS_NONE } },
      { OS_FREEBSD,           OS_FREEBSD,       "FreeBSD",        0,          1,    { OS_FREEBSD_2X } },
      { OS_FREEBSD_2X,  OS_FREEBSD,       "2.x",                  0,          1,    { OS_FREEBSD_3X } },
      { OS_FREEBSD_3X,  OS_FREEBSD,       "3.x",                  0,          1,    { OS_FREEBSD_4X } },
      { OS_FREEBSD_4X,  OS_FREEBSD,       "4.x",                  0,          3,    { OS_FREEBSD_40, OS_FREEBSD_5X, OS_DFLYBSD } },
      { OS_FREEBSD_40,  OS_FREEBSD,       "4.0",                  0,          1,    { OS_FREEBSD_42 } },
      { OS_FREEBSD_42,  OS_FREEBSD,       "4.2",                  0,          1,    { OS_FREEBSD_44 } },
      { OS_FREEBSD_44,  OS_FREEBSD,       "4.4",                  0,          1,    { OS_FREEBSD_46 } },
      { OS_FREEBSD_46,  OS_FREEBSD,       "4.6",                  0,          1,    { OS_FREEBSD_47 } },
      { OS_FREEBSD_47,  OS_FREEBSD,       "4.7",                  0,          1,    { OS_FREEBSD_48 } },
      { OS_FREEBSD_48,  OS_FREEBSD,       "4.8",                  0,          1,    { OS_FREEBSD_49 } },
      { OS_FREEBSD_49,  OS_FREEBSD,       "4.9",                  0,          1,    { OS_FREEBSD_410 } },
      { OS_FREEBSD_410, OS_FREEBSD,       "4.10",                 0,          1,    { OS_FREEBSD_411 } },
      { OS_FREEBSD_411, OS_FREEBSD,       "4.11",                 0,          0,    { OS_NONE } },
      { OS_FREEBSD_5X,  OS_FREEBSD,       "5.x",                  0,          3,    { OS_FREEBSD_50, OS_FREEBSD_6X, OS_OSX } },
      { OS_FREEBSD_50,  OS_FREEBSD,       "5.0",                  0,          1,    { OS_FREEBSD_51 } },
      { OS_FREEBSD_51,  OS_FREEBSD,       "5.1",                  0,          1,    { OS_FREEBSD_52 } },
      { OS_FREEBSD_52,  OS_FREEBSD,       "5.2",                  0,          1,    { OS_FREEBSD_53 } },
      { OS_FREEBSD_53,  OS_FREEBSD,       "5.3",                  0,          0,    { OS_NONE } },
      { OS_FREEBSD_6X,  OS_FREEBSD,       "6.x",                  0,          0,    { OS_NONE } },
      { OS_OPENBSD,           OS_OPENBSD,       "OpenBSD",        0,          1,    { OS_OPENBSD_2X } },
      { OS_OPENBSD_2X,  OS_OPENBSD,       "2.x",                  0,          2,    { OS_OPENBSD_26, OS_OPENBSD_3X } },
      { OS_OPENBSD_26,  OS_OPENBSD,       "2.6",                  0,          0,    { OS_NONE } },
      { OS_OPENBSD_3X,  OS_OPENBSD,       "3.x",                  0,          1,    { OS_OPENBSD_30 } },
      { OS_OPENBSD_30,  OS_OPENBSD,       "3.0",                  0,          1,    { OS_OPENBSD_33 } },
      { OS_OPENBSD_33,  OS_OPENBSD,       "3.3",                  0,          1,    { OS_OPENBSD_35 } },
      { OS_OPENBSD_35,  OS_OPENBSD,       "3.5",                  0,          1,    { OS_OPENBSD_37 } },
      { OS_OPENBSD_37,  OS_OPENBSD,       "3.7",                  0,          0,    { OS_NONE } },
      { OS_DFLYBSD,           OS_DFLYBSD,       "DFlyBSD",        0,          1,    { OS_DFLYBSD_1X } },
      { OS_DFLYBSD_1X,  OS_DFLYBSD,       "1.x",                  0,          1,    { OS_DFLYBSD_10X } },
      { OS_DFLYBSD_10X, OS_DFLYBSD,       "1.0x",                 0,          1,    { OS_DFLYBSD_12 } },
      { OS_DFLYBSD_12,  OS_DFLYBSD,       "1.2",                  0,          0,    { OS_NONE } },
      /* Apple */
      /* Mac OS */
      { OS_MACOS,             OS_MACOS,         "Mac OS",         0,          1,    { OS_MACOS_8X } },
      { OS_MACOS_8X,          OS_MACOS,         "8.x",                  0,          1,    { OS_MACOS_9X } },
      { OS_MACOS_9X,          OS_MACOS,         "9.x",                  0,          1,    { OS_MACOS_92X } },
      { OS_MACOS_92X,         OS_MACOS,         "9.2.x",          0,          1,    { OS_MACOS_92 } },
      { OS_MACOS_92,          OS_MACOS,         "9.2",                  0,          1,    { OS_MACOS_922 } },
      { OS_MACOS_922,         OS_MACOS,         "9.2.2",          0,          0,    { OS_NONE } },
      /* OS X */
      { OS_OSX,               OS_OSX,                 "OS X",                 0,          1,    { OS_OSX_0 } },
      { OS_OSX_0,             OS_OSX,                 ".0",             0,          1,    { OS_OSX_1 } },
      { OS_OSX_1,             OS_OSX,                 ".1",             0,          1,    { OS_OSX_2 } },
      { OS_OSX_2,             OS_OSX,                 ".2",             0,          1,    { OS_OSX_3 } },
      { OS_OSX_3,             OS_OSX,                 ".3",             0,          1,    { OS_OSX_4 } },
      { OS_OSX_4,             OS_OSX,                 ".4",             0,          1,    { OS_OSX_5 } },
      { OS_OSX_5,             OS_OSX,                 ".5",             0,          0,    { OS_NONE } },
      /* Windows */
      { OS_WIN,               OS_WIN,                 "Win",                  0,          2,    { OS_WIN_311, OS_WIN_NT } },
      { OS_WIN_311,           OS_WIN,                 "3.11",                 0,          1,    { OS_WIN_95 } },
      { OS_WIN_95,            OS_WIN,                 "95",             0,          1,    { OS_WIN_98 } },
      { OS_WIN_98,            OS_WIN,                 "98",             0,          1,    { OS_WIN_ME } },
      { OS_WIN_ME,            OS_WIN,                 "Me",             0,          0,    { OS_NONE } },
      { OS_WIN_NT,            OS_WIN_NT,        "WinNT",          0,          1,    { OS_WIN_NT_3X } },
      { OS_WIN_NT_3X,         OS_WIN_NT,        "3.x",                  0,          1,    { OS_WIN_NT_4X } },
      { OS_WIN_NT_4X,         OS_WIN_NT_4X,     "WinNT 4",        0,          2,    { OS_WIN_NT_40, OS_WIN_NT_50_X } },
      { OS_WIN_NT_40,         OS_WIN_NT_4X,     "SP0",                  0,          1,    { OS_WIN_NT_40_SP1 } },
      { OS_WIN_NT_40_SP1,     OS_WIN_NT_4X,     "SP1",                  0,          1,    { OS_WIN_NT_40_SP2 } },
      { OS_WIN_NT_40_SP2,     OS_WIN_NT_4X,     "SP2",                  0,          1,    { OS_WIN_NT_40_SP3 } },
      { OS_WIN_NT_40_SP3,     OS_WIN_NT_4X,     "SP3",                  0,          1,    { OS_WIN_NT_40_SP4 } },
      { OS_WIN_NT_40_SP4,     OS_WIN_NT_4X,     "SP4",                  0,          1,    { OS_WIN_NT_40_SP5 } },
      { OS_WIN_NT_40_SP5,     OS_WIN_NT_4X,     "SP5",                  0,          1,    { OS_WIN_NT_40_SP6 } },
      { OS_WIN_NT_40_SP6,     OS_WIN_NT_4X,     "SP6",                  0,          1,    { OS_WIN_NT_40_SP6A } },
      { OS_WIN_NT_40_SP6A,OS_WIN_NT_4X,   "SP6a",                 0,          0,    { OS_NONE } },
      { OS_WIN_NT_50_X, OS_WIN_NT_50_X,   "Win2K",          0,          3,    { OS_WIN_NT_50, OS_WIN_NT_51_X, OS_WIN_NT_52_X } },
      { OS_WIN_NT_50,         OS_WIN_NT_50_X,   "SP0",                  0,          2,    { OS_WIN_NT_50_SVR, OS_WIN_NT_50_SP1 } },
      { OS_WIN_NT_50_SVR,     OS_WIN_NT_50_SVR,"Win2K Server",0,        0,    { OS_NONE } },
      { OS_WIN_NT_50_SP1,     OS_WIN_NT_50_X,   "SP1",                  0,          1,    { OS_WIN_NT_50_SP2 } },
      { OS_WIN_NT_50_SP2,     OS_WIN_NT_50_X,   "SP2",                  0,          1,    { OS_WIN_NT_50_SP3 } },
      { OS_WIN_NT_50_SP3,     OS_WIN_NT_50_X,   "SP3",                  0,          1,    { OS_WIN_NT_50_SP4 } },
      { OS_WIN_NT_50_SP4,     OS_WIN_NT_50_X,   "SP4",                  0,          0,    { OS_NONE } },
      { OS_WIN_NT_51_X, OS_WIN_NT_51_X,   "WinXP",          0,          2,    { OS_WIN_NT_51, OS_WIN_NT_52_X } },
      { OS_WIN_NT_51,         OS_WIN_NT_51_X,   "SP0",                  0,          1,    { OS_WIN_NT_51_SP1 } },
      { OS_WIN_NT_51_SP1,     OS_WIN_NT_51_X,   "SP1",                  0,          1,    { OS_WIN_NT_51_SP2 } },
      { OS_WIN_NT_51_SP2,     OS_WIN_NT_51_X,   "SP2",                  0,          0,    { OS_NONE } },
      { OS_WIN_NT_52_X, OS_WIN_NT_52_X,   "Win2K3",         0,          1,    { OS_WIN_NT_52 } },
      { OS_WIN_NT_52,         OS_WIN_NT_52_X,   "SP0",                  0,          1,    { OS_WIN_NT_52_SP1  } },
      { OS_WIN_NT_52_SP1,     OS_WIN_NT_52_X,   "SP1",                  0,          0,    { OS_NONE } },
      /* Linux */
      { OS_LINUX,             OS_LINUX,         "Linux",          0,          1,    { OS_LINUX_1X } },
      { OS_LINUX_1X,          OS_LINUX,         "1.x",                  0,          1,    { OS_LINUX_2X } },
      { OS_LINUX_2X,          OS_LINUX,         "2.x",                  0,          1,    { OS_LINUX_20X } },
      { OS_LINUX_20X,         OS_LINUX,         "2.0.x",          0,          1,    { OS_LINUX_22X } },
      { OS_LINUX_22X,         OS_LINUX,         "2.2.x",          0,          1,    { OS_LINUX_24X } },
      { OS_LINUX_24X,         OS_LINUX,         "2.4.x",          0,          2,    { OS_LINUX_2418, OS_LINUX_25X } },
      { OS_LINUX_2418,  OS_LINUX,         "2.4.18",         0,          0,    { OS_NONE } },
      { OS_LINUX_25X,         OS_LINUX,         "2.5.x",          0,          1,    { OS_LINUX_26X } },
      { OS_LINUX_26X,         OS_LINUX,         "2.6.x",          0,          1,    { OS_LINUX_267 } },
      { OS_LINUX_267,         OS_LINUX,         "2.6.7",          0,          1,    { OS_LINUX_268 } },
      { OS_LINUX_268,         OS_LINUX,         "2.6.8",          0,          0,    { OS_NONE } },
      /* Sun Solaris */
      { OS_SOLARIS,           OS_SOLARIS,       "Solaris",        0,          1,    { OS_SOLARIS_25 } },
      { OS_SOLARIS_25,  OS_SOLARIS,       "2.5",                  0,          1,    { OS_SOLARIS_251 } },
      { OS_SOLARIS_251, OS_SOLARIS,       "2.5.1",          0,          0,    { OS_NONE } },
      { OS_SOLARIS_26,  OS_SOLARIS,       "2.6",                  0,          1,    { OS_SOLARIS_7 } },
      { OS_SOLARIS_7,         OS_SOLARIS,       "7",              0,          1,    { OS_SOLARIS_8 } },
      { OS_SOLARIS_8,         OS_SOLARIS,       "8",              0,          1,    { OS_SOLARIS_9 } },
      { OS_SOLARIS_9,         OS_SOLARIS,       "9",              0,          1,    { OS_SOLARIS_10 } },
      { OS_SOLARIS_10,  OS_SOLARIS,       "10",             0,          0,    { OS_NONE } },
      /* Cisco IOS */
      { OS_IOS,               OS_IOS,                 "IOS",                  0,          1,    { OS_IOS_11X } },
      { OS_IOS_11X,           OS_IOS,                 "11.x",                 0,          1,    { OS_IOS_12X } },
      { OS_IOS_12X,           OS_IOS,                 "12.x",                 0,          0,    { OS_NONE } },
      { OS_IOS_PIX,           OS_IOS_PIX,       "PIX",                  0,          1,    { OS_IOS_PIX_5X } },
      { OS_IOS_PIX_5X,  OS_IOS_PIX,       "5.x",                  0,          1,    { OS_IOS_PIX_6X } },
      { OS_IOS_PIX_6X,  OS_IOS_PIX,       "6.x",                  0,          0,    { OS_NONE } },
      /* Novell Netware */
      { OS_NETWARE,           OS_NETWARE,       "Netware",        0,          1,    { OS_NETWARE_5X } },
      { OS_NETWARE_5X,  OS_NETWARE,       "5.x",                  0,          2,    { OS_NETWARE_50, OS_NETWARE_6X } },
      { OS_NETWARE_50,  OS_NETWARE_50,    "Netware 5.0",    0,          0,    { OS_NONE } },
      { OS_NETWARE_6X,  OS_NETWARE,       "6.x",                  0,          1,    { OS_NETWARE_60 } },
      { OS_NETWARE_60,  OS_NETWARE_60,    "Netware 6.0",    0,          1,    { OS_NETWARE_60_SP5 } },
      { OS_NETWARE_60_SP5,OS_NETWARE_60,  "SP5",                  0,          0,    { OS_NONE } },

      /* * * * * * Embedded OSes * * * * */

      /*id                    family                  name_short        release     chcntchild */

      /* Moxa Technologies NPort Express Serial<->Ethernet Bridges */
      { OS_MOXA_NPORT_EXP,OS_MOXA_NPORT_EXP,"Moxa NPort Express", 0,    0,{ OS_NONE } },

      /* Symbol Technologies Spectrum24 Client Bridge CB-1000-0000-US */
      { OS_SYMBOL_SPEC24,     OS_SYMBOL_SPEC24,"Symbol Spec24 Bridge",0,      0,{ OS_NONE } },

      /* Atop Technologies GW Series */
      { OS_ATOP_GW,           OS_ATOP_GW,       "Atop GW",        0,          1,    { OS_ATOP_GW21SW_MAXI } },
      { OS_ATOP_GW21SW_MAXI,OS_ATOP_GW,   "21SW MAXI",      0,          0,    { OS_NONE } },

      /* Perl IOLan */
      { OS_PERLE_IOLAN, OS_PERLE_IOLAN,   "IOLAN",          0,          0,    { OS_NONE } },

      /* VMWare */
      { OS_VMWARE,            OS_VMWARE,        "VMWare",         0,          1,    { OS_VMWARE_5X } },
      { OS_VMWARE_5X,         OS_VMWARE,        "5.x",                  0,          0,    { OS_NONE } },

      /* 3Com Wireless Workgroup Bridge */
      { OS_3COM_WWB,          OS_3COM_WWB,      "3COM WWB",       0,          0,    { OS_NONE } },

      /* Debug */
      { OS_DEBUG_HIGHLIGHT, OS_DEBUG_HIGHLIGHT, "Highlight",      0,    0,    { OS_NONE } },

      /* fin */
};

#define OS_COUNT ((sizeof OS_Config / sizeof OS_Config[0]))

/**
 * the final machine-workable structure
 */
00197 typedef struct {
      os_config config;
      int level; /* dynamically-calculate tree depth */
      int work; /*  */
      int parent_count;
      int parent[OS_TREE_MAXPARENTS];
} os;


static os OS[OS_COUNT]; /* working-copy tree */

static int OS_Roots[OS_COUNT]; /* list of all parentless entries */
static int OS_Roots_Count = 0;

static os OS_Scratch[OS_COUNT]; /* scratch space for destructive sorting */


/* local functions */
static char * os_get_name(int os, char *buf, size_t buflen);
static int os_find_loop(void);
static void os_subtree_print(int index, int indent);
static void os_subtree_print_simple(int index, int indent);
static void os_tree_print(void);


/**
 * check the tree for errors and initialize dynamically-calculated data
 * if we find any errors we print a descriptive error msg so the coder can
 * fix the tree
 */
int os_tree_init(void)
{
      int i;

      i = os_find_loop();
      if (-1 != i) {
            fprintf(stderr, "os_tree_init() argh! \"%s\" loops back on itself! fix it!",
                  OS_Config[i].name_short);
            exit(EXIT_FAILURE);
      }

      /* copy OS_Config to OS */
      memset(&OS, 0, sizeof OS);
      for (i = 0; i < (int)OS_COUNT; i++)
            OS[i].config = OS_Config[i];

      /* calculate levels, parents */
      {
            int j, level, child;

            OS[0].level = 0;
            OS[1].level = 0;
      
            for (i = 1; i < (int)OS_COUNT; i++) {
                  level = OS[i].level;
                  for (j = 0; j < OS[i].config.child_count; j++) {
                        child = OS[i].config.child[j];
                        /* level... */
                        OS[child].level = level + 1;
                        /* parents... */
                        if ((size_t)OS[child].parent_count >= sizeof OS[child].parent / sizeof OS[child].parent[0]) {
                              fprintf(stderr, "OS[%d] OS_TREE_MAXPARENTS is too small! (%u >= %u) fix it!\n",
                                    i, OS[j].parent_count, OS_TREE_MAXPARENTS);
                              exit(EXIT_FAILURE);
                        }
                        OS[child].parent[OS[child].parent_count++] = i;
                  }
            }

            /* record roots */
            for (i = 1; i < (int)OS_COUNT; i++)
                  if (0 == OS[i].level)
                        OS_Roots[OS_Roots_Count++] = i;

            /* write tree in .dot format for reference */
            do {
                  FILE *f;
                  int j;
                  char parent[OS_BUFLEN], child[OS_BUFLEN];

                  f = fopen(OS_GRAPH_FILE, "w");
                  if (NULL == f)
                        break;
                  fprintf(f, "digraph {\n");
                  for (i = 1; i < (int)OS_COUNT; i++) {
                        parent[0] = '\0';
                        (void)os_get_name(i, parent, sizeof parent);
                        for (j = 0; j < OS[i].config.child_count; j++) {
                              child[0] = '\0';
                              fprintf(f, "\"%s\" -> \"%s\";\n", parent,
                                    os_get_name(OS[i].config.child[j], child, sizeof child));
                        }
                        if (0 == j) /* no children */
                              fprintf(f, "\"%s\";\n", parent);
                  }
                  fprintf(f, "}\n");
                  fclose(f);
            } while (0);

      }

      return 0;
}

/**
 *
 */
static char * os_get_name(int os, char *buf, size_t buflen)
{
#ifdef _DEBUG
      assert(NULL != buf);
#endif

      if (0 == buflen)
            return buf;

      /* NOTE: always concat, might be something in buffer already */
      (void)strlcat(buf, OS[OS[os].config.family].config.name_short, buflen);
      if (OS[OS[os].config.family].config.id != OS[os].config.id) {
            if (OS[os].config.name_short[0] != '.') /* don't add a space for version numbers */
                  (void)strlcat(buf, " ", buflen);
            (void)strlcat(buf, OS[os].config.name_short, buflen);
      }

      return buf;
}


/**
 * @return index of the first entry that has its self as a child (shouldn't
 * happen!), or -1 if life is good
 */
static int os_find_loop(void)
{
      int i, j;

      for (i = 1; i < (int)OS_COUNT; i++) {
            for (j = 0; j < OS_Config[i].child_count; j++) {
                  if (i == OS_Config[i].child[j])
                        return i; /* yikes! */
            }
      }
      return -1;
}

/**
 * recursively print an os entry
 */
static void os_subtree_print_simple(int index, int indent)
{
      int i;
      char namebuf[OS_BUFLEN];
      os *os = &OS[index];

      for (i = 0; i < indent; i++)
            printf(" ");

      printf("%s\n", os_get_name(index, namebuf, sizeof namebuf));

      for (i = 0; i < os->config.child_count; i++)
            os_subtree_print_simple(os->config.child[i], indent + 1);
      
}


/**
 * display 
 */
static void os_subtree_print(int index, int indent)
{
      int i;
      char namebuf[OS_BUFLEN] = "";
      os *os = &OS[index];

      for (i = 0; i < indent; i++)
            printf(" ");

      printf("#%d %s (level:%d,work:%d)\n",
            os->config.id, os_get_name(index, namebuf, sizeof namebuf), os->level, os->work);

      for (i = 0; i < os->config.child_count; i++)
            os_subtree_print(os->config.child[i], indent + 1);
      
}

/**
 * print the entire tree
 */
static void os_tree_print(void)
{
      int i, j;
      int orphans[OS_COUNT] = { 0 };

      /* find orphans */
      for (i = 1; i < (int)OS_COUNT; i++)
            for (j = 0; j < OS[i].config.child_count; j++)
                  orphans[OS[i].config.child[j]]++;

      /* print each subtree */
      for (i = 1; i < (int)OS_COUNT; i++)
            if (0 == orphans[i])
                  os_subtree_print(i, 0);

}

/**
 * add weight to os and all its children
 * @param os
 * @param weight
 * @param os_stop where to stop applying the weight; os_stop is exclusive
 * unless equal to os or OS_NONE
 * @note recursion without recursive function calls
 */
void os_tree_apply(int os, int weight, int os_stop)
{
      int curr, total, add;
      int children[OS_COUNT], seen[OS_COUNT] = { 0 };

      children[0] = os;
      total = 1;

      for (
            curr = 0;
            curr < total && (OS_NONE == os_stop || os_stop >= children[curr]);
            curr++
      ) {
            OS[children[curr]].work += weight;
            if (os_stop == os)
                  break;
            for (add = 0; add < OS[children[curr]].config.child_count; add++) {
                  if (0 == seen[OS[children[curr]].config.child[add]]) {
                        seen[OS[children[curr]].config.child[add]] = 1;
                        children[total++] = OS[children[curr]].config.child[add];
                  }
            }
      }
}

/**
 * print os array as a table, not a tree
 * used for inspecting OS_Scratch post-sort
 */
static void os_table_print(os *table, int non_zero)
{
      os *os = table;
      int len = OS_COUNT, i = 0;
      char buf[OS_BUFLEN];

      while (len--) {
            if (!non_zero || os->work) {
                  buf[0] = '\0';
                  printf("%d. #%d [%s] (%d)\n", i++, os->config.id,
                        os_get_name(OS[table[os - table].config.id].config.id, buf, sizeof buf),
                        os->work);
                  os++;
            }
      }
}

/**
 * callback passed to qsort to sort OS
 */
static int os_cmp(const void *va, const void *vb)
{
      const os *a, *b;
#ifdef _DEBUG
      assert(NULL != va);
      assert(NULL != vb);
#endif
      a = va, b = vb;
      if (a->work != b->work) { /* higher total weight */
            return (a->work > b->work ? -1 : 1);
      } else {
            return a->config.id - b->config.id; /* sort by "age" in heriarchy */
      }
}

/**
 * once weights have been applied, see who looks good
 */
static void os_sort(void)
{
      memcpy(OS_Scratch, OS, sizeof OS); /* copy to scratch for messing around */
      qsort(OS_Scratch, OS_COUNT, sizeof OS[0], os_cmp);
}

/**
 * post-sort put together a single description of the top-ranking OS_Scratch records
 * TODO:
 * \ul
 * \li "fuzzy" matching, figure out %
 * \li summarize better... if all BSDs are equal, say "BSD"
 * \li use "first+" instead of "first-last"
 * \ul
 */
void os_calculate(char *buf, size_t buflen)
{
      int i,
            fam_count; /* count consecutive equal family members */
      os *last = OS_Scratch + 0;

      buf[0] = '\0';

      os_sort();

      (void)os_get_name(OS_Scratch[0].config.id, buf, buflen);
      if (OS_UNKNOWN == OS_Scratch[0].config.id || OS_Scratch[0].level <= 1) {
            return; /* unknown, bail */
      }

      for (
            fam_count = 0, i = 1;
            OS_Scratch[i].work == last->work && i < (int)OS_COUNT;
            i++
      ) {
            if (OS_Scratch[i].config.family != last->config.family) {
                  if (fam_count > 0) { /* print previous, which was last in family */
                        if (0 == OS_Scratch[i - 1].config.child_count && last->config.id != last->config.family) {
                              /* we've gone all the way to the end, and we're not describing an entire family */
                              strlcat(buf, "+", buflen);
                        } else if (OS_Scratch[i - 1].config.family != last->config.id) {
                              strlcat(buf, "-", buflen);
                              strlcat(buf, OS_Scratch[i - 1].config.name_short, buflen);
                        }
                  }
                  strlcat(buf, "/", buflen); /* add comma and family and name */
                  (void)os_get_name(OS_Scratch[i].config.id, buf, buflen);
                  fam_count = 0;
                  last = OS_Scratch + i;
            } else {
                  fam_count++;
            }
      }

      if (fam_count > 0 && OS_Scratch[i - 1].level >= last->level && OS_Scratch[i - 1].config.family) {
            if (OS_Scratch[0].config.family != OS_Scratch[0].config.id) {
                  if (0 == OS_Scratch[i - 1].config.child_count && last->config.id != last->config.family) { /* we've gone all the way to the end */
                        strlcat(buf, "+", buflen);
                  } else { /* some range */
                        strlcat(buf, "-", buflen);
                        strlcat(buf, OS_Scratch[i - 1].config.name_short, buflen);
                  }
            }
      }

#ifdef _DEBUG
#if 0
      os_tree_print();
      printf("summary: %s\n", buf);
      printf("i: %d, fam_count:%d, family: %d, level: %d\n",
            i, fam_count, last->config.family, OS_Scratch[i - 1].level);
#endif
      os_table_print(OS_Scratch, 1);
#endif

}

/**
 * clear out "work" value from OS
 */
void os_tree_reset(void)
{
      size_t i;
      for (i = 0; i < OS_COUNT; i++)
            OS[i].work = 0;
}

#ifdef STANDALONE_CLASSIFY
/**
 *
 */
int main(void)
{
      char os_guess[OS_BUFLEN];

      printf("sizeof OS: %d bytes, each entry: %d bytes, entries: %d\n",
            sizeof OS, sizeof OS[0], OS_COUNT);

      os_tree_init();

      /* test "apply" */
      /* FIXME: unit test! */
#if 0
      os_tree_apply(OS_WIN_NT_51_SP1, 3, OS_NONE);
      os_tree_apply(OS_WIN_NT_50_SP2, 3, OS_WIN_NT_50_SP4);
#endif

#if 0
      os_tree_apply(OS_LINUX, 3, OS_NONE);
#endif

      os_tree_apply(OS_FREEBSD_4X, 1, OS_FREEBSD_5X);
      os_tree_apply(OS_LINUX, 1, OS_LINUX);

      //os_tree_apply(OS_NETBSD_1X, 1, OS_NONE);

#if 0
      os_tree_apply(OS_FREEBSD_3X, 10, OS_NONE);
#endif

#if 0
      os_tree_apply(OS_WIN_NT, 8, OS_NONE);
      os_tree_apply(OS_OSX, 4, OS_NONE);
#endif

      os_calculate(os_guess, sizeof os_guess);
      printf("calc: %s\n", os_guess);
      
      return 0;
}
#endif



Generated by  Doxygen 1.6.0   Back to index