/*
 	Check_cisco checks various snmp statistics related to Cisco devices.
    Copyright (C) 2012  Jason Harris

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <stdio.h>
#include <string.h>

/* Define useful variables */
#define MISSING_OPTIONS "Unknown or missing options.\n"
#define RESULT_OK 0
#define RESULT_WARNING 1
#define RESULT_CRITICAL 2
#define RESULT_UNKNOWN 3

/* Global Variables */
char retstr[120];
int exitVal = RESULT_UNKNOWN, warn = 80, crit = 90;
char mode[20];

/* Function Definitions */
char *checkMem(struct snmp_session* session);
char *checkCPU(struct snmp_session* session);
char *checkFailover(struct snmp_session* session);
char *checkSessions(struct snmp_session* session);
char *checkInterfaceTraffic(struct snmp_session* session);
char *checkTemp(struct snmp_session* session);
char *check3750Temp(struct snmp_session* session);

/*
  Print usage info.
*/
void usage(void) {
	fprintf(stderr, "USAGE: check_cisco ");
	snmp_parse_args_usage(stderr);
	fprintf(stderr, " [OID]\n\n");
	snmp_parse_args_descriptions(stderr);
	fprintf(stderr, "Application specific options.\n");
	fprintf(stderr, "  -C APPOPTS\n");
	fprintf(stderr, "\t\t\t  c:  Set the critical threshold.\n");
	fprintf(stderr, "\t\t\t  m:  Set the operation mode [cpu|failover|memory|sessions|temp|3750temp]\n");
	fprintf(stderr, "\t\t\t  w:  Set the warning threshold.\n");
}

/*
  Process input options.
*/
void optProc(int argc, char *const *argv, int opt) {
	switch (opt) {
		case 'C':
			while (*optarg) {
				switch (*optarg++) {
					case 'c':
						crit = atoi(argv[optind++]);
						break;
					case 'm':
						strcpy(mode, argv[optind++]);
						break;
					case 'w':
						warn = atoi(argv[optind++]);
						break;
				}
			}
	break;
	}
}

/* Main program 
	Queries various SNMP values on cisco devices.
*/
int main(int argc, char *argv[]) {
	char* output;
	struct snmp_session session;
	char arg;
	int i;
	long snmpVer;

	/* Initialize and build snmp session, add version, community, host, etc */
	init_snmp("Cisco_checks");
	
	snmp_sess_init( &session );

	switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
	case -3:
		exit(1);
	case -2:
		exit(0);
	case -1:
		usage();
		exit(1);
	default:
		break;
	}
	
	/* Check warning/critical test values to verify they are within the appropriate ranges */
	if ((crit > 100) && (strcmp(mode, "sessions"))) {
		printf("Critical threshold should be less than 100!\n");
		usage();
		exit(RESULT_UNKNOWN);
	}
	else if (crit < 0) {
		printf("Critical threshould must be greater than 0!\n");
		usage();
		exit(RESULT_UNKNOWN);
	}
	else if ((warn < 0) && (strcmp(mode, "sessions"))) {
		printf("Warning threshold must be greater than or equal to 0!\n");
		usage();
		exit(RESULT_UNKNOWN);
	}
	else if (warn > crit) {
		printf("Warning threshold must not be greater than critical threshold!\n");
		usage();
		exit(RESULT_UNKNOWN);
	}
		

	/* Check mode selection and run appropriate function */
	if ((strcmp(mode, "memory")) == 0) {
		output = checkMem(&session);
	}
	else if ((strcmp(mode, "cpu")) == 0) {
		output = checkCPU(&session);
	}
	else if ((strcmp(mode, "failover")) == 0) {
		output = checkFailover(&session);
	}
	else if ((strcmp(mode, "sessions")) == 0) {
		output = checkSessions(&session);
	}
	else if ((strcmp(mode, "temp")) == 0) {
		output = checkTemp(&session);
	}
	else if ((strcmp(mode, "3750temp")) == 0) {
		output = check3750Temp(&session);
	}
	else {
		printf(MISSING_OPTIONS);
		usage();
		exit(RESULT_UNKNOWN);
	}

	printf("%s", output);
	return exitVal;
}

/*
  Check the failover status of a Cisco Firewall.
*/
char *checkFailover(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int status, primStatus = 0, secStatus = 0;
	char primaryStatus[10], secondaryStatus[10];
	oid mib_primary[] = {1, 3, 6, 1, 4, 1, 9, 9, 147, 1, 2, 1, 1, 1, 3, 6};
	oid mib_secondary[] = {1, 3, 6, 1, 4, 1, 9, 9, 147, 1, 2, 1, 1, 1, 3, 7};

	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	/* Create PDU and add desired OIDs */
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	snmp_add_null_var(pdu, mib_primary, OID_LENGTH(mib_primary));
	snmp_add_null_var(pdu, mib_secondary, OID_LENGTH(mib_secondary));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}
	
	/* Read out the data returned from the device, exit if data returned is NULL */
	vars = reply->variables;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}

	primStatus = (int)(*vars->val.integer); /* store the failover status for the primary firewall */

	vars = vars->next_variable;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}

	secStatus = (int)(*vars->val.integer); /* store the failover status for the secondary firewall */

	/* Check the primary status and secondary status, and set return values */
	switch (primStatus) {
		case 3:
			strcpy(primaryStatus, "Down");
			switch (secStatus) {
				case 3:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Down");
					break;
				case 4:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Error");
					break;
				case 9:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Active");
					break;
				case 10:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Standby");
					break;
				default:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Unknown");
			}
			break;
		case 4:
			strcpy(primaryStatus, "Error");
			switch (secStatus) {
				case 3:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Down");
					break;
				case 4:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Error");
					break;
				case 9:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Active");
					break;
				case 10:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Standby");
					break;
				default:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Unknown");
			}
			break;
		case 9:
			strcpy(primaryStatus, "Active");
			switch (secStatus) {
				case 3:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Down");
					break;
				case 4:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Error");
					break;
				case 9:
					exitVal = RESULT_OK;
					strcpy(secondaryStatus, "Active");
					break;
				case 10:
					exitVal = RESULT_OK;
					strcpy(secondaryStatus, "Standby");
					break;
				default:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Unknown");
			}
			break;
		case 10:
			strcpy(primaryStatus, "Standby");
			switch (secStatus) {
				case 3:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Down");
					break;
				case 4:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Error");
					break;
				case 9:
					exitVal = RESULT_WARNING;
					strcpy(secondaryStatus, "Active");
					break;
				case 10:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Standby");
					break;
				default:
					exitVal = RESULT_CRITICAL;
					strcpy(secondaryStatus, "Unknown");
			}
			break;
		default:
			strcpy(secondaryStatus, "Unknown");
			strcpy(primaryStatus, "Unknown");
			exitVal = RESULT_UNKNOWN;
	}

	/* Check status (OK/WARN/CRIT) and print appropriate message */
	switch (exitVal) {
		case RESULT_OK:
			sprintf(retstr, "OK - Primary: %s, Secondary: %s\n", primaryStatus, secondaryStatus);
			break;
		case RESULT_WARNING:
			sprintf(retstr, "WARNING - Primary: %s, Secondary: %s\n", primaryStatus, secondaryStatus);
			break;
		case RESULT_CRITICAL:
			sprintf(retstr, "CRITICAL - Primary: %s, Secondary: %s\n", primaryStatus, secondaryStatus);
			break;
		default:
			sprintf(retstr, "Either no value was returned from the device or no status could be determined.\n");
	}

	/* Release the reserved resources as they are no longer needed */
	snmp_free_pdu(reply);
	snmp_close(s_handle);

	return retstr;
}

/*
  Check the number of current active open sessions.
*/
char *checkSessions(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int status, cur_sessions, max_sessions;

	oid mib_cur_sessions[] = { 1, 3, 6, 1, 4, 1, 9, 9, 147, 1, 2, 2, 2, 1, 5, 40, 6 };
	oid mib_max_sessions[] = { 1, 3, 6, 1, 4, 1, 9, 9, 147, 1, 2, 2, 2, 1, 5, 40, 7 };

	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	snmp_add_null_var(pdu, mib_cur_sessions, OID_LENGTH(mib_cur_sessions));
	snmp_add_null_var(pdu, mib_max_sessions, OID_LENGTH(mib_max_sessions));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}

	vars = reply->variables;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	cur_sessions = (int)*vars->val.integer;
	vars = vars->next_variable;
	max_sessions = (int)*vars->val.integer;

	if (cur_sessions > crit) {
		exitVal=RESULT_CRITICAL;
		sprintf(retstr, "CRITICAL - Current Sessions: %i, Max Sessions: %i\n", cur_sessions, max_sessions);
	}
	else if (cur_sessions > warn) {
		exitVal=RESULT_WARNING;
		sprintf(retstr, "WARNING - Current Sessions: %i, Max Sessions: %i\n", cur_sessions, max_sessions);
	}
	else {
		exitVal = RESULT_OK;
		sprintf(retstr, "OK - Current Sessions: %i, Max Sessions: %i\n", cur_sessions, max_sessions);
	}

	snmp_free_pdu(reply);
	snmp_close(s_handle);

	return retstr;
}

/*
  Check the CPU load percentage on Cisco Devices.
*/
char *checkCPU(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int status, CPU5sec, CPU1min, CPU5min;

	oid mib_CPU5sec[] = {1, 3, 6, 1, 4, 1, 9, 9, 109, 1, 1, 1, 1, 3, 1};
	oid mib_CPU1min[] = {1, 3, 6, 1, 4, 1, 9, 9, 109, 1, 1, 1, 1, 4, 1};
	oid mib_CPU5min[] = {1, 3, 6, 1, 4, 1, 9, 9, 109, 1, 1, 1, 1, 5, 1};
	
	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	/* Build PDU and add desired OID's */
	pdu = snmp_pdu_create(SNMP_MSG_GET);

	snmp_add_null_var(pdu, mib_CPU5sec, OID_LENGTH(mib_CPU5sec));
	snmp_add_null_var(pdu, mib_CPU1min, OID_LENGTH(mib_CPU1min));
	snmp_add_null_var(pdu, mib_CPU5min, OID_LENGTH(mib_CPU5min));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}

	/* Read out data returned from device, print error if data is NULL */
	vars = reply->variables;
	if ((vars == NULL) || (vars->type == ASN_NULL)) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	CPU5sec = (int)(*vars->val.integer);
	
	vars = vars->next_variable;
	if ((vars == NULL) || (vars->type == ASN_NULL)) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	CPU1min = (int)(*vars->val.integer);

	vars = vars->next_variable;
	if ((vars == NULL) || (vars->type == ASN_NULL)) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	CPU5min = (int)(*vars->val.integer);

	/* Check data from device against crit/warn limits, set return string accordingly */
	if (CPU5min > crit) {
		exitVal = RESULT_CRITICAL;
		sprintf(retstr, "CRITICAL - CPU Load: 5sec (%i%%) - 1min (%i%%) - 5min (%i%%)\n", CPU5sec, CPU1min, CPU5min);
	}
	else if (CPU5min > warn) {
		exitVal = RESULT_WARNING;
		sprintf(retstr, "CRITICAL - CPU Load: 5sec (%i%%) - 1min (%i%%) - 5min (%i%%)\n", CPU5sec, CPU1min, CPU5min);
	}
	else {
		exitVal = RESULT_OK;
		sprintf(retstr, "OK - CPU Load: 5sec (%i%%) - 1min (%i%%) - 5min (%i%%)\n", CPU5sec, CPU1min, CPU5min);
	}

	snmp_free_pdu(reply);
	snmp_close(s_handle);
	return retstr;
}

/*
  Check the memory usage on Cisco Devices.
*/
char *checkMem(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int status;
	float used_mem = 0;
	float free_mem = 0;
	float total_mem = 0;
	float used_percent = 0;
	float free_percent = 0;
	
	oid mib_used_mem[] = { 1, 3, 6, 1, 4, 1, 9, 9, 48, 1, 1, 1, 5, 1 };
	oid mib_free_mem[] = { 1, 3, 6, 1, 4, 1, 9, 9, 48, 1, 1, 1, 6, 1 };
	oid mib_int_name[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2, 10101 };

	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	/* Build PDU and add desired OIDs */
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	
	snmp_add_null_var(pdu, mib_used_mem, OID_LENGTH(mib_used_mem));
	snmp_add_null_var(pdu, mib_free_mem, OID_LENGTH(mib_free_mem));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}

	/* Read out data returned from device, print error if data is NULL */
	vars = reply->variables;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	used_mem = ((float)*(vars->val.integer)) / (1024*1024);
	
	vars = vars->next_variable;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}
	free_mem = ((float)*(vars->val.integer)) / (1024*1024);
	
	/* Calculate info based on data returned from device */
	total_mem = used_mem + free_mem;
	used_percent = (used_mem / total_mem) * 100;
	free_percent = (free_mem / total_mem) * 100;

	/* Check info against crit/warn levels and print message accordingly */
	if (used_percent > crit) {
		exitVal=RESULT_CRITICAL;
		sprintf(retstr, "CRITICAL - Total mem: %.0fMB used mem: %.2f MB (%.2f%%), free mem: %.2f MB (%.2f%%)\n", total_mem, used_mem, used_percent, free_mem, free_percent);
	}
	else if (used_percent > warn) {
		exitVal=RESULT_WARNING;
		sprintf(retstr, "WARNING - Total mem: %.0fMB used mem: %.2fMB (%.2f%%), free mem: %.2f MB (%.2f%%)\n", total_mem, used_mem, used_percent, free_mem, free_percent);
	}
	else if (used_percent > 0) {
		exitVal=RESULT_OK;
		sprintf(retstr, "OK - Total mem: %.0fMB used mem: %.2f MB (%.2f%%), free mem: %.2f MB (%.2f%%)\n", total_mem, used_mem, used_percent, free_mem, free_percent);
	}
	else {
		exitVal=RESULT_UNKNOWN;
		sprintf(retstr, "UNKNOWN - No data received from device.");
	}

	snmp_free_pdu(reply);
	snmp_close(s_handle);
	return retstr;
}

/*
	Check temperature on cisco devices.
*/
char *checkTemp(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int temp, status;
	oid mib_temp[] = {1, 3, 6, 1, 4, 1, 9, 9, 13, 1, 3, 1, 3, 1006};

	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	/* Create PDU and add desired OIDs */
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	snmp_add_null_var(pdu, mib_temp, OID_LENGTH(mib_temp));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}
	
	/* Read out the data returned from the device, exit if data returned is NULL */
	vars = reply->variables;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}

	temp = (int)(*vars->val.integer); /* store the temperature */

	/* Check the temperature */
	if (temp >= crit) {
		exitVal = RESULT_CRITICAL;
	}
	else if (temp >= warn) {
		exitVal = RESULT_WARNING;
	}
	else {
		exitVal = RESULT_OK;
	}

	/* Check status (OK/WARN/CRIT) and print appropriate message */
	switch (exitVal) {
		case RESULT_OK:
			sprintf(retstr, "OK - Temp = %i\n", temp);
			break;
		case RESULT_WARNING:
			sprintf(retstr, "WARNING - Temp = %i\n", temp);
			break;
		case RESULT_CRITICAL:
			sprintf(retstr, "CRITICAL - Temp = %i\n", temp);
			break;
		default:
			sprintf(retstr, "Either no value was returned from the device or no status could be determined.\n");
	}

	/* Release the reserved resources as they are no longer needed */
	snmp_free_pdu(reply);
	snmp_close(s_handle);

	return retstr;
}

/*
	Check temperature on Cisco 3750E.
*/
char *check3750Temp(struct snmp_session* session) {
	struct snmp_session *s_handle = NULL;
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *reply = NULL;
	struct variable_list *vars;
	int temp, status;
	oid mib_temp[] = {1, 3, 6, 1, 4, 1, 9, 9, 13, 1, 3, 1, 3, 1005};

	/* Open snmp session, print error if one occurs */
	s_handle = snmp_open( session );
	if (!s_handle) {
		printf("ERROR - Problem opening session!\n");
		exit(RESULT_CRITICAL);
	}
	
	/* Create PDU and add desired OIDs */
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	snmp_add_null_var(pdu, mib_temp, OID_LENGTH(mib_temp));
	
	/* Check if snmp synchs correctly, if not exit the program */
	status = snmp_synch_response(s_handle, pdu, &reply);
	if (status == STAT_ERROR) {
		printf("ERROR - Problem while querying device!\n");
		exit(RESULT_CRITICAL);
	}
	else if (status == STAT_TIMEOUT) {
		printf("ERROR - Connection timed out!\n");
		exit(RESULT_CRITICAL);
	}
	else if (reply->errstat != SNMP_ERR_NOERROR) {
		switch (reply->errstat) {
			case SNMP_ERR_NOSUCHNAME:
				printf("ERROR - Device does not support that feature!\n");
				break;
			case SNMP_ERR_TOOBIG:
				printf("ERROR - Result generated too much data!\n");
				break;
			case SNMP_ERR_READONLY:
				printf("ERROR - Value is read only!\n");
				break;
			case SNMP_ERR_BADVALUE:
			case SNMP_ERR_GENERR:
			case SNMP_ERR_NOACCESS:
			case SNMP_ERR_WRONGTYPE:
			case SNMP_ERR_WRONGLENGTH:
			case SNMP_ERR_WRONGENCODING:
			case SNMP_ERR_WRONGVALUE:
			case SNMP_ERR_NOCREATION:
			case SNMP_ERR_INCONSISTENTVALUE:
			case SNMP_ERR_RESOURCEUNAVAILABLE:
			case SNMP_ERR_COMMITFAILED:
			case SNMP_ERR_UNDOFAILED:
			case SNMP_ERR_AUTHORIZATIONERROR:
			case SNMP_ERR_NOTWRITABLE:
			case SNMP_ERR_INCONSISTENTNAME:
			default:
				printf("ERROR - Unknown error!\n");
		}
		exit(RESULT_CRITICAL);
	}
	
	/* Read out the data returned from the device, exit if data returned is NULL */
	vars = reply->variables;
	if (vars->type == ASN_NULL) {
		printf("ERROR - No data recieved from device\n");
		exit(RESULT_UNKNOWN);
	}

	temp = (int)(*vars->val.integer); /* store the temperature */

	/* Check the temperature */
	if (temp >= crit) {
		exitVal = RESULT_CRITICAL;
	}
	else if (temp >= warn) {
		exitVal = RESULT_WARNING;
	}
	else {
		exitVal = RESULT_OK;
	}

	/* Check status (OK/WARN/CRIT) and print appropriate message */
	switch (exitVal) {
		case RESULT_OK:
			sprintf(retstr, "OK - Temp = %i\n", temp);
			break;
		case RESULT_WARNING:
			sprintf(retstr, "WARNING - Temp = %i\n", temp);
			break;
		case RESULT_CRITICAL:
			sprintf(retstr, "CRITICAL - Temp = %i\n", temp);
			break;
		default:
			sprintf(retstr, "Either no value was returned from the device or no status could be determined.\n");
	}

	/* Release the reserved resources as they are no longer needed */
	snmp_free_pdu(reply);
	snmp_close(s_handle);

	return retstr;
}