net-snmp
5.4.1
|
00001 /* 00002 * Host Resources MIB - utility functions - hr_utils.c 00003 * 00004 */ 00005 00006 00007 #include <net-snmp/net-snmp-config.h> 00008 #include <sys/types.h> 00009 #if HAVE_NETINET_IN_H 00010 #include <netinet/in.h> 00011 #endif 00012 #if HAVE_STDLIB_H 00013 #include <stdlib.h> 00014 #endif 00015 #include <ctype.h> 00016 #if HAVE_STRING_H 00017 #include <string.h> 00018 #endif 00019 #if HAVE_STDLIB_H 00020 #include <stdlib.h> 00021 #endif 00022 00023 #if TIME_WITH_SYS_TIME 00024 #ifdef WIN32 00025 # include <sys/timeb.h> 00026 #else 00027 # include <sys/time.h> 00028 #endif 00029 # include <time.h> 00030 #else 00031 # if HAVE_SYS_TIME_H 00032 # include <sys/time.h> 00033 # else 00034 # include <time.h> 00035 # endif 00036 #endif 00037 00038 #include <net-snmp/types.h> 00039 #include <net-snmp/library/snmp-tc.h> /* for "internal" definitions */ 00040 #include <net-snmp/library/snmp_api.h> 00041 00042 /* 00043 DateAndTime ::= TEXTUAL-CONVENTION 00044 DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d" 00045 STATUS current 00046 DESCRIPTION 00047 "A date-time specification. 00048 00049 field octets contents range 00050 ----- ------ -------- ----- 00051 1 1-2 year* 0..65536 00052 2 3 month 1..12 00053 3 4 day 1..31 00054 4 5 hour 0..23 00055 5 6 minutes 0..59 00056 6 7 seconds 0..60 00057 (use 60 for leap-second) 00058 7 8 deci-seconds 0..9 00059 8 9 direction from UTC '+' / '-' 00060 9 10 hours from UTC* 0..13 00061 10 11 minutes from UTC 0..59 00062 00063 * Notes: 00064 - the value of year is in network-byte order 00065 - daylight saving time in New Zealand is +13 00066 00067 For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be 00068 displayed as: 00069 00070 1992-5-26,13:30:15.0,-4:0 00071 00072 Note that if only local time is known, then timezone 00073 information (fields 8-10) is not present." 00074 SYNTAX OCTET STRING (SIZE (8 | 11)) 00075 */ 00076 00077 int 00078 netsnmp_dateandtime_set_buf_from_vars(u_char *buf, size_t *bufsize, 00079 u_short year, u_char month, u_char day, 00080 u_char hour, u_char minutes, 00081 u_char seconds, u_char deci_seconds, 00082 int utc_offset_direction, 00083 u_char utc_offset_hours, 00084 u_char utc_offset_minutes) 00085 { 00086 u_short tmp_year = htons(year); 00087 00088 /* 00089 * if we have a utc offset, need 11 bytes. Otherwise we 00090 * just need 8 bytes. 00091 */ 00092 if(utc_offset_direction) { 00093 if(*bufsize < 11) 00094 return SNMPERR_RANGE; 00095 00096 /* 00097 * set utc offset data 00098 */ 00099 buf[8] = (utc_offset_direction < 0) ? '-' : '+'; 00100 buf[9] = utc_offset_hours; 00101 buf[10] = utc_offset_minutes; 00102 *bufsize = 11; 00103 } 00104 else if(*bufsize < 8) 00105 return SNMPERR_RANGE; 00106 else 00107 *bufsize = 8; 00108 00109 /* 00110 * set basic date/time data 00111 */ 00112 memcpy(buf, &tmp_year, sizeof(tmp_year)); 00113 buf[2] = month; 00114 buf[3] = day; 00115 buf[4] = hour; 00116 buf[5] = minutes; 00117 buf[6] = seconds; 00118 buf[7] = deci_seconds; 00119 00120 return SNMPERR_SUCCESS; 00121 } 00122 00123 u_char * 00124 date_n_time(time_t * when, size_t * length) 00125 { 00126 struct tm *tm_p; 00127 static u_char string[11]; 00128 unsigned short yauron; 00129 00130 /* 00131 * Null time 00132 */ 00133 if (when == NULL || *when == 0 || *when == (time_t) - 1) { 00134 string[0] = 0; 00135 string[1] = 0; 00136 string[2] = 1; 00137 string[3] = 1; 00138 string[4] = 0; 00139 string[5] = 0; 00140 string[6] = 0; 00141 string[7] = 0; 00142 *length = 8; 00143 return string; 00144 } 00145 00146 00147 /* 00148 * Basic 'local' time handling 00149 */ 00150 tm_p = localtime(when); 00151 yauron = tm_p->tm_year + 1900; 00152 string[0] = (u_char)(yauron >> 8); 00153 string[1] = (u_char)yauron; 00154 string[2] = tm_p->tm_mon + 1; 00155 string[3] = tm_p->tm_mday; 00156 string[4] = tm_p->tm_hour; 00157 string[5] = tm_p->tm_min; 00158 string[6] = tm_p->tm_sec; 00159 string[7] = 0; 00160 *length = 8; 00161 00162 #ifndef cygwin 00163 /* 00164 * Timezone offset 00165 */ 00166 { 00167 #ifdef STRUCT_TM_HAS_TM_GMTOFF 00168 const int tzoffset = tm_p->tm_gmtoff; 00169 #else 00170 const int tzoffset = timezone; 00171 #endif 00172 if (tzoffset > 0) 00173 string[8] = '-'; 00174 else 00175 string[8] = '+'; 00176 string[9] = abs(tzoffset) / 3600; 00177 string[10] = (abs(tzoffset) - string[9] * 3600) / 60; 00178 *length = 11; 00179 } 00180 #endif 00181 00182 #ifdef SYSV 00183 /* 00184 * Daylight saving time 00185 */ 00186 if (tm_p->tm_isdst > 0) { 00187 /* 00188 * Assume add one hour 00189 */ 00190 if (string[8] == '-') 00191 --string[9]; 00192 else 00193 ++string[9]; 00194 00195 if (string[9] == 0) 00196 string[8] = '+'; 00197 } 00198 #endif 00199 00200 return string; 00201 } 00202 00203 00204 time_t 00205 ctime_to_timet(char *str) 00206 { 00207 struct tm tm; 00208 00209 if (strlen(str) < 24) 00210 return 0; 00211 00212 /* 00213 * Month 00214 */ 00215 if (!strncmp(str + 4, "Jan", 3)) 00216 tm.tm_mon = 0; 00217 else if (!strncmp(str + 4, "Feb", 3)) 00218 tm.tm_mon = 1; 00219 else if (!strncmp(str + 4, "Mar", 3)) 00220 tm.tm_mon = 2; 00221 else if (!strncmp(str + 4, "Apr", 3)) 00222 tm.tm_mon = 3; 00223 else if (!strncmp(str + 4, "May", 3)) 00224 tm.tm_mon = 4; 00225 else if (!strncmp(str + 4, "Jun", 3)) 00226 tm.tm_mon = 5; 00227 else if (!strncmp(str + 4, "Jul", 3)) 00228 tm.tm_mon = 6; 00229 else if (!strncmp(str + 4, "Aug", 3)) 00230 tm.tm_mon = 7; 00231 else if (!strncmp(str + 4, "Sep", 3)) 00232 tm.tm_mon = 8; 00233 else if (!strncmp(str + 4, "Oct", 3)) 00234 tm.tm_mon = 9; 00235 else if (!strncmp(str + 4, "Nov", 3)) 00236 tm.tm_mon = 10; 00237 else if (!strncmp(str + 4, "Dec", 3)) 00238 tm.tm_mon = 11; 00239 else 00240 return 0; 00241 00242 tm.tm_mday = atoi(str + 8); 00243 tm.tm_hour = atoi(str + 11); 00244 tm.tm_min = atoi(str + 14); 00245 tm.tm_sec = atoi(str + 17); 00246 tm.tm_year = atoi(str + 20) - 1900; 00247 00248 /* 00249 * Cope with timezone and DST 00250 */ 00251 00252 #ifdef SYSV 00253 if (daylight) 00254 tm.tm_isdst = 1; 00255 00256 tm.tm_sec -= timezone; 00257 #endif 00258 00259 return (mktime(&tm)); 00260 } 00261 00262 /* 00263 * blatantly lifted from opensmp 00264 */ 00265 char 00266 check_rowstatus_transition(int oldValue, int newValue) 00267 { 00268 /* 00269 * From the SNMPv2-TC MIB: 00270 * STATE 00271 * +--------------+-----------+-------------+------------- 00272 * | A | B | C | D 00273 * | |status col.|status column| 00274 * |status column | is | is |status column 00275 * ACTION |does not exist| notReady | notInService| is active 00276 * --------------+--------------+-----------+-------------+------------- 00277 * set status |noError ->D|inconsist- |inconsistent-|inconsistent- 00278 * column to | or | entValue| Value| Value 00279 * createAndGo |inconsistent- | | | 00280 * | Value| | | 00281 * --------------+--------------+-----------+-------------+------------- 00282 * set status |noError see 1|inconsist- |inconsistent-|inconsistent- 00283 * column to | or | entValue| Value| Value 00284 * createAndWait |wrongValue | | | 00285 * --------------+--------------+-----------+-------------+------------- 00286 * set status |inconsistent- |inconsist- |noError |noError 00287 * column to | Value| entValue| | 00288 * active | | | | 00289 * | | or | | 00290 * | | | | 00291 * | |see 2 ->D|see 8 ->D| ->D 00292 * --------------+--------------+-----------+-------------+------------- 00293 * set status |inconsistent- |inconsist- |noError |noError ->C 00294 * column to | Value| entValue| | 00295 * notInService | | | | 00296 * | | or | | or 00297 * | | | | 00298 * | |see 3 ->C| ->C|see 6 00299 * --------------+--------------+-----------+-------------+------------- 00300 * set status |noError |noError |noError |noError ->A 00301 * column to | | | | or 00302 * destroy | ->A| ->A| ->A|see 7 00303 * --------------+--------------+-----------+-------------+------------- 00304 * set any other |see 4 |noError |noError |see 5 00305 * column to some| | | | 00306 * value | | see 1| ->C| ->D 00307 * --------------+--------------+-----------+-------------+------------- 00308 00309 * (1) goto B or C, depending on information available to the 00310 * agent. 00311 00312 * (2) if other variable bindings included in the same PDU, 00313 * provide values for all columns which are missing but 00314 * required, and all columns have acceptable values, then 00315 * return noError and goto D. 00316 00317 * (3) if other variable bindings included in the same PDU, 00318 * provide legal values for all columns which are missing but 00319 * required, then return noError and goto C. 00320 00321 * (4) at the discretion of the agent, the return value may be 00322 * either: 00323 00324 * inconsistentName: because the agent does not choose to 00325 * create such an instance when the corresponding 00326 * RowStatus instance does not exist, or 00327 00328 * inconsistentValue: if the supplied value is 00329 * inconsistent with the state of some other MIB object's 00330 * value, or 00331 00332 * noError: because the agent chooses to create the 00333 * instance. 00334 00335 * If noError is returned, then the instance of the status 00336 * column must also be created, and the new state is B or C, 00337 * depending on the information available to the agent. If 00338 * inconsistentName or inconsistentValue is returned, the row 00339 * remains in state A. 00340 00341 * (5) depending on the MIB definition for the column/table, 00342 * either noError or inconsistentValue may be returned. 00343 00344 * (6) the return value can indicate one of the following 00345 * errors: 00346 00347 * wrongValue: because the agent does not support 00348 * notInService (e.g., an agent which does not support 00349 * createAndWait), or 00350 00351 * inconsistentValue: because the agent is unable to take 00352 * the row out of service at this time, perhaps because it 00353 * is in use and cannot be de-activated. 00354 00355 * (7) the return value can indicate the following error: 00356 00357 * inconsistentValue: because the agent is unable to 00358 * remove the row at this time, perhaps because it is in 00359 * use and cannot be de-activated. 00360 00361 * (8) the transition to D can fail, e.g., if the values of the 00362 * conceptual row are inconsistent, then the error code would 00363 * be inconsistentValue. 00364 00365 * NOTE: Other processing of (this and other varbinds of) the 00366 * set request may result in a response other than noError 00367 * being returned, e.g., wrongValue, noCreation, etc. 00368 */ 00369 00370 switch (newValue) { 00371 /* 00372 * these two end up being equivelent as far as checking the 00373 */ 00374 /* 00375 * status goes, although the final states are based on the 00376 */ 00377 /* 00378 * newValue. 00379 */ 00380 case RS_ACTIVE: 00381 case RS_NOTINSERVICE: 00382 if (oldValue == RS_NOTINSERVICE || oldValue == RS_ACTIVE); 00383 else 00384 return SNMP_ERR_INCONSISTENTVALUE; 00385 break; 00386 00387 case RS_NOTREADY: 00388 /* 00389 * Illegal set value. 00390 */ 00391 return SNMP_ERR_WRONGVALUE; 00392 break; 00393 00394 case RS_CREATEANDGO: 00395 if (oldValue != RS_NONEXISTENT) 00396 /* 00397 * impossible, we already exist. 00398 */ 00399 return SNMP_ERR_INCONSISTENTVALUE; 00400 break; 00401 00402 case RS_CREATEANDWAIT: 00403 if (oldValue != RS_NONEXISTENT) 00404 /* 00405 * impossible, we already exist. 00406 */ 00407 return SNMP_ERR_INCONSISTENTVALUE; 00408 break; 00409 00410 case RS_DESTROY: 00411 break; 00412 00413 default: 00414 return SNMP_ERR_WRONGVALUE; 00415 break; 00416 } 00417 00418 return SNMP_ERR_NOERROR; 00419 } 00420 00421 char 00422 check_storage_transition(int oldValue, int newValue) 00423 { 00424 /* 00425 * From the SNMPv2-TC MIB: 00426 00427 * "Describes the memory realization of a conceptual row. A 00428 * row which is volatile(2) is lost upon reboot. A row which 00429 * is either nonVolatile(3), permanent(4) or readOnly(5), is 00430 * backed up by stable storage. A row which is permanent(4) 00431 * can be changed but not deleted. A row which is readOnly(5) 00432 * cannot be changed nor deleted. 00433 00434 * If the value of an object with this syntax is either 00435 * permanent(4) or readOnly(5), it cannot be written. 00436 * Conversely, if the value is either other(1), volatile(2) or 00437 * nonVolatile(3), it cannot be modified to be permanent(4) or 00438 * readOnly(5). (All illegal modifications result in a 00439 * 'wrongValue' error.) 00440 00441 * Every usage of this textual convention is required to 00442 * specify the columnar objects which a permanent(4) row must 00443 * at a minimum allow to be writable." 00444 */ 00445 switch (oldValue) { 00446 case SNMP_STORAGE_PERMANENT: 00447 case SNMP_STORAGE_READONLY: 00448 return SNMP_ERR_INCONSISTENTVALUE; 00449 00450 case SNMP_STORAGE_NONE: 00451 case SNMP_STORAGE_OTHER: 00452 case SNMP_STORAGE_VOLATILE: 00453 case SNMP_STORAGE_NONVOLATILE: 00454 if (newValue == SNMP_STORAGE_PERMANENT || 00455 newValue == SNMP_STORAGE_READONLY) 00456 return SNMP_ERR_INCONSISTENTVALUE; 00457 } 00458 00459 return SNMP_ERR_NOERROR; 00460 }