Icinga-core 1.4.0
next gen monitoring
common/shared.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * SHARED.C - Random utility function for Icinga shared by CGIs and Core
00004  *
00005  * Copyright (c) 2010-2011 Nagios Core Development Team and Community Contributors
00006  * Copyright (c) 2010-2011 Icinga Development Team (http://www.icinga.org)
00007  *
00008  * License:
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License version 2 as
00012  * published by the Free Software Foundation.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022  *
00023  *****************************************************************************/
00024 
00025 
00026 #include "../include/config.h"
00027 #include "../include/common.h"
00028 
00029 extern int date_format;
00030 
00031 /* fix the problem with strtok() skipping empty options between tokens */
00032 char *my_strtok(char *buffer, char *tokens)
00033 {
00034         char *token_position = NULL;
00035         char *sequence_head = NULL;
00036         static char *my_strtok_buffer = NULL;
00037         static char *original_my_strtok_buffer = NULL;
00038 
00039         if (buffer != NULL) {
00040                 my_free(original_my_strtok_buffer);
00041                 if ((my_strtok_buffer = (char *)strdup(buffer)) == NULL)
00042                         return NULL;
00043                 original_my_strtok_buffer = my_strtok_buffer;
00044         }
00045 
00046         sequence_head = my_strtok_buffer;
00047 
00048         if (sequence_head[0] == '\x0')
00049                 return NULL;
00050 
00051         token_position = strchr(my_strtok_buffer, tokens[0]);
00052 
00053         if (token_position == NULL) {
00054                 my_strtok_buffer = strchr(my_strtok_buffer, '\x0');
00055                 return sequence_head;
00056         }
00057 
00058         token_position[0] = '\x0';
00059         my_strtok_buffer = token_position + 1;
00060 
00061         return sequence_head;
00062 }
00063 
00064 /* fixes compiler problems under Solaris, since strsep() isn't included */
00065 /* this code is taken from the glibc source */
00066 char *my_strsep(char **stringp, const char *delim)
00067 {
00068         char *begin, *end;
00069 
00070         begin = *stringp;
00071         if (begin == NULL)
00072                 return NULL;
00073 
00074         /* A frequent case is when the delimiter string contains only one
00075          * character.  Here we don't need to call the expensive `strpbrk'
00076          * function and instead work using `strchr'.  */
00077         if (delim[0] == '\0' || delim[1] == '\0') {
00078                 char ch = delim[0];
00079 
00080                 if (ch == '\0' || begin[0] == '\0')
00081                         end = NULL;
00082                 else {
00083                         if (*begin == ch)
00084                                 end = begin;
00085                         else
00086                                 end = strchr(begin + 1, ch);
00087                 }
00088         } else {
00089                 /* find the end of the token.  */
00090                 end = strpbrk(begin, delim);
00091         }
00092 
00093         if (end) {
00094                 /* terminate the token and set *STRINGP past NUL character.  */
00095                 *end++ = '\0';
00096                 *stringp = end;
00097         } else
00098                 /* no more delimiters; this is the last token.  */
00099                 *stringp = NULL;
00100 
00101         return begin;
00102 }
00103 
00104 /* open a file read-only via mmap() */
00105 mmapfile *mmap_fopen(char *filename)
00106 {
00107         mmapfile *new_mmapfile = NULL;
00108         int fd = 0;
00109         void *mmap_buf = NULL;
00110         struct stat statbuf;
00111         int mode = O_RDONLY;
00112         unsigned long file_size = 0L;
00113 
00114         if (filename == NULL)
00115                 return NULL;
00116 
00117         /* allocate memory */
00118         if ((new_mmapfile = (mmapfile *) malloc(sizeof(mmapfile))) == NULL)
00119                 return NULL;
00120 
00121         /* open the file */
00122         if ((fd = open(filename, mode)) == -1) {
00123                 my_free(new_mmapfile);
00124                 return NULL;
00125         }
00126 
00127         /* get file info */
00128         if ((fstat(fd, &statbuf)) == -1) {
00129                 close(fd);
00130                 my_free(new_mmapfile);
00131                 return NULL;
00132         }
00133 
00134         /* get file size */
00135         file_size = (unsigned long)statbuf.st_size;
00136 
00137         /* only mmap() if we have a file greater than 0 bytes */
00138         if (file_size > 0) {
00139 
00140                 /* mmap() the file - allocate one extra byte for processing zero-byte files */
00141                 if ((mmap_buf =
00142                      (void *)mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd,
00143                                   0)) == MAP_FAILED) {
00144                         close(fd);
00145                         my_free(new_mmapfile);
00146                         return NULL;
00147                 }
00148         } else
00149                 mmap_buf = NULL;
00150 
00151         /* populate struct info for later use */
00152         new_mmapfile->path = (char *)strdup(filename);
00153         new_mmapfile->fd = fd;
00154         new_mmapfile->file_size = (unsigned long)file_size;
00155         new_mmapfile->current_position = 0L;
00156         new_mmapfile->current_line = 0L;
00157         new_mmapfile->mmap_buf = mmap_buf;
00158 
00159         return new_mmapfile;
00160 }
00161 
00162 /* close a file originally opened via mmap() */
00163 int mmap_fclose(mmapfile * temp_mmapfile)
00164 {
00165 
00166         if (temp_mmapfile == NULL)
00167                 return ERROR;
00168 
00169         /* un-mmap() the file */
00170         if (temp_mmapfile->file_size > 0L)
00171                 munmap(temp_mmapfile->mmap_buf, temp_mmapfile->file_size);
00172 
00173         /* close the file */
00174         close(temp_mmapfile->fd);
00175 
00176         /* free memory */
00177         my_free(temp_mmapfile->path);
00178         my_free(temp_mmapfile);
00179 
00180         return OK;
00181 }
00182 
00183 /* gets one line of input from an mmap()'ed file */
00184 char *mmap_fgets(mmapfile * temp_mmapfile)
00185 {
00186         char *buf = NULL;
00187         unsigned long x = 0L;
00188         int len = 0;
00189 
00190         if (temp_mmapfile == NULL)
00191                 return NULL;
00192 
00193         /* size of file is 0 bytes */
00194         if (temp_mmapfile->file_size == 0L)
00195                 return NULL;
00196 
00197         /* we've reached the end of the file */
00198         if (temp_mmapfile->current_position >= temp_mmapfile->file_size)
00199                 return NULL;
00200 
00201         /* find the end of the string (or buffer) */
00202         for (x = temp_mmapfile->current_position; x < temp_mmapfile->file_size;
00203              x++) {
00204                 if (*((char *)(temp_mmapfile->mmap_buf) + x) == '\n') {
00205                         x++;
00206                         break;
00207                 }
00208         }
00209 
00210         /* calculate length of line we just read */
00211         len = (int)(x - temp_mmapfile->current_position);
00212 
00213         /* allocate memory for the new line */
00214         if ((buf = (char *)malloc(len + 1)) == NULL)
00215                 return NULL;
00216 
00217         /* copy string to newly allocated memory and terminate the string */
00218         memcpy(buf,
00219                ((char *)(temp_mmapfile->mmap_buf) +
00220                 temp_mmapfile->current_position), len);
00221         buf[len] = '\x0';
00222 
00223         /* update the current position */
00224         temp_mmapfile->current_position = x;
00225 
00226         /* increment the current line */
00227         temp_mmapfile->current_line++;
00228 
00229         return buf;
00230 }
00231 
00232 /* gets one line of input from an mmap()'ed file (may be contained on more than one line in the source file) */
00233 char *mmap_fgets_multiline(mmapfile * temp_mmapfile)
00234 {
00235         char *buf = NULL;
00236         char *tempbuf = NULL;
00237         char *stripped = NULL;
00238         int len = 0;
00239         int len2 = 0;
00240         int end = 0;
00241 
00242         if (temp_mmapfile == NULL)
00243                 return NULL;
00244 
00245         while (1) {
00246 
00247                 my_free(tempbuf);
00248 
00249                 if ((tempbuf = mmap_fgets(temp_mmapfile)) == NULL)
00250                         break;
00251 
00252                 if (buf == NULL) {
00253                         len = strlen(tempbuf);
00254                         if ((buf = (char *)malloc(len + 1)) == NULL)
00255                                 break;
00256                         memcpy(buf, tempbuf, len);
00257                         buf[len] = '\x0';
00258                 } else {
00259                         /* strip leading white space from continuation lines */
00260                         stripped = tempbuf;
00261                         while (*stripped == ' ' || *stripped == '\t')
00262                                 stripped++;
00263                         len = strlen(stripped);
00264                         len2 = strlen(buf);
00265                         if ((buf =
00266                              (char *)realloc(buf, len + len2 + 1)) == NULL)
00267                                 break;
00268                         strcat(buf, stripped);
00269                         len += len2;
00270                         buf[len] = '\x0';
00271                 }
00272 
00273                 if (len == 0)
00274                         break;
00275 
00276                 /* handle Windows/DOS CR/LF */
00277                 if (len >= 2 && buf[len - 2] == '\r')
00278                         end = len - 3;
00279                 /* normal Unix LF */
00280                 else if (len >= 1 && buf[len - 1] == '\n')
00281                         end = len - 2;
00282                 else
00283                         end = len - 1;
00284 
00285                 /* two backslashes found. unescape first backslash first and break */
00286                 if (end >= 1 && buf[end - 1] == '\\' && buf[end] == '\\') {
00287                         buf[end] = '\n';
00288                         buf[end + 1] = '\x0';
00289                         break;
00290                 }
00291 
00292                 /* one backslash found. continue reading the next line */
00293                 else if (end > 0 && buf[end] == '\\')
00294                         buf[end] = '\x0';
00295 
00296                 /* no continuation marker was found, so break */
00297                 else
00298                         break;
00299         }
00300 
00301         my_free(tempbuf);
00302 
00303         return buf;
00304 }
00305 
00306 /* strip newline, carriage return, and tab characters from beginning and end of a string */
00307 void strip(char *buffer)
00308 {
00309         register int x, z;
00310         int len;
00311 
00312         if (buffer == NULL || buffer[0] == '\x0')
00313                 return;
00314 
00315         /* strip end of string */
00316         len = (int)strlen(buffer);
00317         for (x = len - 1; x >= 0; x--) {
00318                 switch (buffer[x]) {
00319                 case ' ': case '\n': case '\r': case '\t':
00320                         buffer[x] = '\x0';
00321                         continue;
00322                 }
00323                 break;
00324         }
00325 
00326         /* if we stripped all of it, just return */
00327         if (!x)
00328                 return;
00329 
00330         /* save last position for later... */
00331         z = x;
00332 
00333         /* strip beginning of string (by shifting) */
00334         /* NOTE: this is very expensive to do, so avoid it whenever possible */
00335         for (x = 0;; x++) {
00336                 switch (buffer[x]) {
00337                 case ' ': case '\n': case '\r': case '\t':
00338                         continue;
00339                 }
00340                 break;
00341         }
00342 
00343         if (x > 0 && z > 0) {
00344                 /* new length of the string after we stripped the end */
00345                 len = z + 1;
00346 
00347                 /* shift chars towards beginning of string to remove leading whitespace */
00348                 for (z = x; z < len; z++)
00349                         buffer[z - x] = buffer[z];
00350                 buffer[len - x] = '\x0';
00351         }
00352 }
00353 
00354 /**************************************************
00355  *************** HASH FUNCTIONS *******************
00356  **************************************************/
00357 /* dual hash function */
00358 int hashfunc(const char *name1, const char *name2, int hashslots)
00359 {
00360         unsigned int i, result;
00361 
00362         result = 0;
00363 
00364         if (name1)
00365                 for (i = 0; i < strlen(name1); i++)
00366                         result += name1[i];
00367 
00368         if (name2)
00369                 for (i = 0; i < strlen(name2); i++)
00370                         result += name2[i];
00371 
00372         result = result % hashslots;
00373 
00374         return result;
00375 }
00376 
00377 /* dual hash data comparison */
00378 int compare_hashdata(const char *val1a, const char *val1b, const char *val2a,
00379                      const char *val2b)
00380 {
00381         int result = 0;
00382 
00383         /* NOTE: If hash calculation changes, update the compare_strings() function! */
00384 
00385         /* check first name */
00386         if (val1a == NULL && val2a == NULL)
00387                 result = 0;
00388         else if (val1a == NULL)
00389                 result = 1;
00390         else if (val2a == NULL)
00391                 result = -1;
00392         else
00393                 result = strcmp(val1a, val2a);
00394 
00395         /* check second name if necessary */
00396         if (result == 0) {
00397                 if (val1b == NULL && val2b == NULL)
00398                         result = 0;
00399                 else if (val1b == NULL)
00400                         result = 1;
00401                 else if (val2b == NULL)
00402                         result = -1;
00403                 else
00404                         result = strcmp(val1b, val2b);
00405         }
00406 
00407         return result;
00408 }
00409 /*
00410  * given a date/time in time_t format, produce a corresponding
00411  * date/time string, including timezone
00412  */
00413 void get_datetime_string(time_t * raw_time, char *buffer, int buffer_length,
00414                          int type)
00415 {
00416         time_t t;
00417         struct tm *tm_ptr, tm_s;
00418         int hour;
00419         int minute;
00420         int second;
00421         int month;
00422         int day;
00423         int year;
00424         char *weekdays[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00425         char *months[12] =
00426             { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept",
00427      "Oct", "Nov", "Dec" };
00428         char *tzone = "";
00429 
00430         if (raw_time == NULL)
00431                 time(&t);
00432         else
00433                 t = *raw_time;
00434 
00435         if (type == HTTP_DATE_TIME)
00436                 tm_ptr = gmtime_r(&t, &tm_s);
00437         else
00438                 tm_ptr = localtime_r(&t, &tm_s);
00439 
00440         hour = tm_ptr->tm_hour;
00441         minute = tm_ptr->tm_min;
00442         second = tm_ptr->tm_sec;
00443         month = tm_ptr->tm_mon + 1;
00444         day = tm_ptr->tm_mday;
00445         year = tm_ptr->tm_year + 1900;
00446 
00447 #ifdef HAVE_TM_ZONE
00448         tzone = (char *)(tm_ptr->tm_zone);
00449 #else
00450         tzone = (tm_ptr->tm_isdst) ? tzname[1] : tzname[0];
00451 #endif
00452 
00453         /* ctime() style date/time */
00454         if (type == LONG_DATE_TIME)
00455                 snprintf(buffer, buffer_length, "%s %s %d %02d:%02d:%02d %s %d",
00456                          weekdays[tm_ptr->tm_wday], months[tm_ptr->tm_mon], day,
00457                          hour, minute, second, tzone, year);
00458 
00459         /* short date/time */
00460         else if (type == SHORT_DATE_TIME) {
00461                 if (date_format == DATE_FORMAT_EURO)
00462                         snprintf(buffer, buffer_length,
00463                                  "%02d-%02d-%04d %02d:%02d:%02d", day, month,
00464                                  year, hour, minute, second);
00465                 else if (date_format == DATE_FORMAT_ISO8601
00466                          || date_format == DATE_FORMAT_STRICT_ISO8601)
00467                         snprintf(buffer, buffer_length,
00468                                  "%04d-%02d-%02d%c%02d:%02d:%02d", year, month,
00469                                  day,
00470                                  (date_format ==
00471                                   DATE_FORMAT_STRICT_ISO8601) ? 'T' : ' ', hour,
00472                                  minute, second);
00473                 else
00474                         snprintf(buffer, buffer_length,
00475                                  "%02d-%02d-%04d %02d:%02d:%02d", month, day,
00476                                  year, hour, minute, second);
00477         }
00478 
00479         /* short date */
00480         else if (type == SHORT_DATE) {
00481                 if (date_format == DATE_FORMAT_EURO)
00482                         snprintf(buffer, buffer_length, "%02d-%02d-%04d", day,
00483                                  month, year);
00484                 else if (date_format == DATE_FORMAT_ISO8601
00485                          || date_format == DATE_FORMAT_STRICT_ISO8601)
00486                         snprintf(buffer, buffer_length, "%04d-%02d-%02d", year,
00487                                  month, day);
00488                 else
00489                         snprintf(buffer, buffer_length, "%02d-%02d-%04d", month,
00490                                  day, year);
00491         }
00492 
00493         /* expiration date/time for HTTP headers */
00494         else if (type == HTTP_DATE_TIME)
00495                 snprintf(buffer, buffer_length,
00496                          "%s, %02d %s %d %02d:%02d:%02d GMT",
00497                          weekdays[tm_ptr->tm_wday], day, months[tm_ptr->tm_mon],
00498                          year, hour, minute, second);
00499 
00500         /* short time */
00501         else
00502                 snprintf(buffer, buffer_length, "%02d:%02d:%02d", hour, minute,
00503                          second);
00504 
00505         buffer[buffer_length - 1] = '\x0';
00506 }
00507 
00508 /* get days, hours, minutes, and seconds from a raw time_t format or total seconds */
00509 void get_time_breakdown(unsigned long raw_time, int *days, int *hours,
00510                         int *minutes, int *seconds)
00511 {
00512         unsigned long temp_time;
00513         int temp_days;
00514         int temp_hours;
00515         int temp_minutes;
00516         int temp_seconds;
00517 
00518         temp_time = raw_time;
00519 
00520         temp_days = temp_time / 86400;
00521         temp_time -= (temp_days * 86400);
00522         temp_hours = temp_time / 3600;
00523         temp_time -= (temp_hours * 3600);
00524         temp_minutes = temp_time / 60;
00525         temp_time -= (temp_minutes * 60);
00526         temp_seconds = (int)temp_time;
00527 
00528         *days = temp_days;
00529         *hours = temp_hours;
00530         *minutes = temp_minutes;
00531         *seconds = temp_seconds;
00532 }
 All Data Structures Files Functions Variables Typedefs Defines