/* C application that demonstrates how to export data to SNMP via fsubagent. */ #include "dprint.h" #include "fsubagent.h" #include "podunk_rr_mib.h" #include #include #include #include /* data file written by this app, read by snmpd's podunk_rr module */ #define SHARED_FNAME "podunk_rr.fsa" /* The object we'll use to export data to SNMP */ fsubagent *g_subagent; /* An arbitrary limit. */ #define MAXTRAINS 10 /* Init routines cut-and-pasted from podunk_rr.c, and trimmed down a bit. * I'm not suggesting this is the best way to structure the init code, but the * similarity between the MIB module code and this app may help people trying * to figure all this out. */ /*------ fleetStatus (a scalar row) -------*/ static fsubagentRow *g_row_fleetStatus = NULL; static void init_fleetStatus(void) { /* just the part of the OID below this module's root */ static int oid_fleetStatus[] = { PODUNK_RR_fleetStatus, fsubagent_END}; g_row_fleetStatus = fsubagent_createScalarRow(g_subagent, oid_fleetStatus, PODUNK_RR_fleetStatus_FORMAT); } /*------ trainEntry -------*/ static fsubagentArray *g_arr_trainEntry = NULL; static void init_trainEntry(void) { static int oid_trainEntry[] = { PODUNK_RR_trainTable, PODUNK_RR_trainEntry, fsubagent_END}; g_arr_trainEntry = fsubagent_createArray(g_subagent, oid_trainEntry, PODUNK_RR_trainEntry_FORMAT); } /*------ carEntry -------*/ static fsubagentArray2 *g_arr2_carEntry = NULL; static void init_carEntry(void) { static int oid_carEntry[] = {PODUNK_RR_carTable, PODUNK_RR_carEntry, fsubagent_END}; g_arr2_carEntry = fsubagent_createArray2(g_subagent, oid_carEntry, PODUNK_RR_carEntry_FORMAT); } /*---------------- end table/row definitions ---------------*/ static int init(void) { int err; /* Create the fsubagent. */ g_subagent = fsubagent_new(); if (!g_subagent) return ENOMEM; /* Bind tables (and scalar rows) to the fsubagent. * PODUNK_RR_INIT is a macro generated by mib2h.pl that just calls * init_xxx for every table and scalar row 'xxx' in the MIB. * You don't have to use this macro -- you could just call the * routines by hand, or do the initialization some other way. */ PODUNK_RR_INIT; /* Bind a filename to the fsubagent. */ fsubagent_setFilename(g_subagent, SHARED_FNAME); /* Load in old rows & values from the file. * If the file doesn't exist yet, don't complain. */ err = fsubagent_load(g_subagent); if (err && (err != ENOENT)) { DPRINT(("demo: can't load\n")); return err; } /* success */ return 0; } /*---------------- end initialization --------------------------*/ /* Demonstrate locating, creating if needed, and updating one SNMP value */ static int demo(const char *trainName, const char *carName) { /* The trainEntry inside trainTable */ int trIndex; fsubagentRow *trRow = NULL; /* The part of carTable corresponding to the given train */ fsubagentArray *trCarArr = NULL; /* The carEntry inside carTable corresponding to the given car and train */ fsubagentRow *carRow = NULL; int err; /* Find (or create) the given train. */ trRow = fsubagentArray_getRowByStr(g_arr_trainEntry, PODUNK_RR_trainName, trainName, &trIndex); if (!trRow) { /* Otherwise create new row */ int trIndex2; trRow = fsubagentArray_createRow(g_arr_trainEntry, &trIndex); if (!trRow) { DPRINT(("demo: can't create train\n")); return ENOMEM; } /* and initialize it (uninit values are zero or empty string) */ err = fsubagentRow_setInt(trRow, PODUNK_RR_trainIndex, trIndex); assert(!err); /* BUG on purpose: demonstrate what happens when you violate the MIB */ err = fsubagentRow_setString(trRow, PODUNK_RR_trainIndex, trainName); assert(err == EINVAL); /* Now do it right */ err = fsubagentRow_setString(trRow, PODUNK_RR_trainName, trainName); assert(!err); /* Update the fleetStatus */ err = fsubagentRow_setInt(g_row_fleetStatus, PODUNK_RR_fsTrainCount, trIndex); assert(!err); /* All but one trains are used; one is kept as a spare, say. */ err = fsubagentRow_setInt(g_row_fleetStatus, PODUNK_RR_fsTrainUsed, trIndex-1); assert(!err); err = fsubagentRow_setInt(g_row_fleetStatus, PODUNK_RR_fsTrainFree, 1); assert(!err); /* create corresponding part of car table */ trCarArr = fsubagentArray2_createArray(g_arr2_carEntry, &trIndex2); if (!trCarArr) { DPRINT(("demo: can't create car for train\n")); return ENOMEM; } /* first index of car table must be same as only index of train table * FIXME: fsubagent should ensure this by construction! */ assert(trIndex == trIndex2); } else { trCarArr = fsubagentArray2_getArray(g_arr2_carEntry, trIndex); if (!trCarArr) { DPRINT(("demo: can't get car array for train\n")); return ENOENT; } } /* OK, we have trRow pointing to the trainEntry, * and trCarArr pointing to that train's part of the carEntry table. */ /* Find (or create) the given car. */ carRow = fsubagentArray_getRowByStr(trCarArr, PODUNK_RR_carName, carName,0); if (!carRow) { /* Otherwise create new row */ int rownum; carRow = fsubagentArray_createRow(trCarArr, &rownum); if (!carRow) { DPRINT(("demo: can't create car\n")); return ENOMEM; } /* and initialize it (uninit values are zero or empty string) */ err = fsubagentRow_setInt(carRow, PODUNK_RR_carIndex, rownum); assert(!err); err = fsubagentRow_setString(carRow, PODUNK_RR_carName, carName); assert(!err); } /* Finally, set it's lastCleaned time to now */ err = fsubagentRow_setInt(carRow, PODUNK_RR_carLastCleaned, time(0)); assert(!err); /* Success */ return 0; } int main(int argc, char **argv) { int err; if (argc != 3) { printf("usage: %s trainName carName\n" "Sets given train's given car's lastCleaned time to 'now'.\n" "If given car/train doesn't exist, it is created.\n", argv[0]); exit(1); } err = init(); if (err) { fprintf(stderr, "Error %d initializing demo. Failed.\n", err); exit(1); } err = demo(argv[1], argv[2]); if (err) { fprintf(stderr, "Error %d running demo. Failed.\n", err); exit(1); } /* Save to disk so snmpd can see the values, and so they persist * to the next run of this app. In a real server, you'd * call fsubagent_save() once a minute or so. */ err = fsubagent_save(g_subagent); if (err) { fprintf(stderr, "Error %d saving demo. Failed.\n", err); exit(1); } exit(0); }