util.c File Reference

General utility routines shared by several modules. More...

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <sys/param.h>
#include <sys/stat.h>
#include "dhash.h"
#include "util.h"
#include "path_utils.h"
#include "logging.h"
#include "inotify_watch.h"
#include "watch_database.h"

Go to the source code of this file.

Defines

#define _GNU_SOURCE
 Turn on GNU extensions.

Functions

int key_string_cmp (const void *_a, const void *_b)
 Callback used by qsort() to compare two hash keys.
int entry_string_cmp (const void *_a, const void *_b)
 Callback used by qsort() to compare two hash entries.
char * keys_string (hash_table_t *table, const char *prefix, const char *suffix)
 Generate a string with the keys of a hash table in sorted order.
char * watch_path_table_string (hash_table_t *table)
 Pretty print the contents of the watch_path_table.
int strip_whitespace (char *str)
 Strip leading and trailing whitespace.
const char * util_error_string (int error)
 Return a static string describing the error code for util errors.
const char * lwatch_error_string (int error)
 Return a static string describing the error code for lwatch.
const char * error_string (int error)
 Return a static string describing the error code.
const char * time_string (time_t t, bool local, const char *fmt)
 Format a time_t value as a string, either in local time or UTC.
const char * file_mode_string (mode_t mode)
 Return the file mode flags as a formatted string.
int get_uid_name (uid_t uid, char **name)
 Given a system uid get the user name as a string.
int get_gid_name (gid_t gid, char **name)
 Given a system gid get the group name as a string.

Variables

int debug = 0
 Global integer value used to indicate debugging level.


Detailed Description

General utility routines shared by several modules.

Definition in file util.c.


Function Documentation

int entry_string_cmp ( const void *  _a,
const void *  _b 
)

Callback used by qsort() to compare two hash entries.

The two parameters are coerced to pointers to hash_entry_t structs. If the key in each entry is not a string it is converted to a string. Then the two key strings are compared and the result returned. The primary use of this function is to produce a sorted list of hash entries.

Definition at line 135 of file util.c.

Referenced by watch_path_table_string().

00136 {
00137     const hash_entry_t *a = _a, *b = _b;
00138     char buf_a[128], buf_b[128];
00139     const char *str_a, *str_b;
00140 
00141     switch(a->key.type) {
00142     case HASH_KEY_STRING:
00143         str_a = a->key.str;
00144         break;
00145     case HASH_KEY_ULONG:
00146         snprintf(buf_a, sizeof(buf_a), "%lu", a->key.ul);
00147         str_a = buf_a;
00148         break;
00149     default:
00150         buf_a[0] = 0;
00151         str_a = buf_a;
00152     }
00153 
00154     switch(b->key.type) {
00155     case HASH_KEY_STRING:
00156         str_b = b->key.str;
00157         break;
00158     case HASH_KEY_ULONG:
00159         snprintf(buf_b, sizeof(buf_b), "%lu", b->key.ul);
00160         str_b = buf_b;
00161         break;
00162     default:
00163         buf_b[0] = 0;
00164         str_b = buf_b;
00165     }
00166 
00167     return strcmp(str_a, str_b);
00168 }

const char* error_string ( int  error  ) 

Return a static string describing the error code.

Parameters:
[in] error The error code
Returns:
Pointer to thread local static string describing the error code.
The error code is tested against each of the known error ranges for modules in this project. If the error matches one of the known internal error ranges then the error_string() function for that module is called and it's result returned. Otherwise the result of strerror() is returned.

Definition at line 417 of file util.c.

Referenced by add_path_to_target_list(), database_lookup_path_info(), database_query_all_paths_iter(), database_query_backups_iter(), database_query_backups_of_target_iter(), database_query_pending_reaps_iter(), database_query_targets_iter(), destroy_path_watch(), destroy_path_watch_if_empty(), dump_database(), find_log_files(), get_create_path_info(), get_path_info_reap_candidacy(), init_path_info(), inotify_cookie_cache_operator(), inotify_start_monitoring(), inotify_stop_monitoring(), inotify_watch_init(), keys_string(), log_set_filepath(), log_set_time_format(), lost_rename_callback(), lwatch_event_callback(), lwatch_fini(), lwatch_init(), main(), main_loop(), new_path_info(), new_path_watch(), populate_path_info(), process_event(), process_file_close(), process_file_create(), process_file_delete(), process_file_modification(), process_file_rename(), process_pending_reaps(), read_events(), reap_file_data(), relocate_watches(), remove_path_from_target_list(), start_monitoring(), track_path_watch(), untrack_path_watch(), update_stat_info(), update_stat_info_and_write(), validate_backups_in_database(), watch_database_init(), and watch_path_table_string().

00418 {
00419     static __thread char buf[256];   /* thread local static buffer for strerror_r() */
00420 
00421     if (IS_HASH_ERROR(error))
00422         return hash_error_string(error);
00423     if (IS_INOTIFY_WATCH_ERROR(error))
00424         return inotify_watch_error_string(error);
00425     if (IS_PATH_UTILS_ERROR(error))
00426         return path_utils_error_string(error);
00427     if (IS_WATCH_DATABASE_ERROR(error))
00428         return watch_database_error_string(error);
00429     if (IS_LWATCH_ERROR(error))
00430         return lwatch_error_string(error);
00431 
00432     strerror_r(error, buf, sizeof(buf));
00433     return buf;
00434 }

const char* file_mode_string ( mode_t  mode  ) 

Return the file mode flags as a formatted string.

Parameters:
[in] mode The file mode flags to be formatted.
Returns:
Returns pointer to a thread local static string
The format of the string is identical to what "ls -l" produces, e.g.: "-rw-r--r--"

Definition at line 480 of file util.c.

Referenced by path_info_string().

00481 {
00482     static __thread char buf[11];
00483 
00484   if (S_ISREG (mode))
00485     buf[0] = '-';
00486   else if (S_ISDIR (mode))
00487     buf[0] = 'd';
00488   else if (S_ISBLK (mode))
00489     buf[0] = 'b';
00490   else if (S_ISCHR (mode))
00491     buf[0] = 'c';
00492   else if (S_ISLNK (mode))
00493     buf[0] = 'l';
00494   else if (S_ISFIFO (mode))
00495     buf[0] = 'p';
00496   else if (S_ISSOCK (mode))
00497     buf[0] = 's';
00498   else
00499     buf[0] = '?';
00500 
00501   buf[1] = mode & S_IRUSR ? 'r' : '-';
00502   buf[2] = mode & S_IWUSR ? 'w' : '-';
00503   buf[3] = (mode & S_ISUID
00504             ? (mode & S_IXUSR ? 's' : 'S')
00505             : (mode & S_IXUSR ? 'x' : '-'));
00506   buf[4] = mode & S_IRGRP ? 'r' : '-';
00507   buf[5] = mode & S_IWGRP ? 'w' : '-';
00508   buf[6] = (mode & S_ISGID
00509             ? (mode & S_IXGRP ? 's' : 'S')
00510             : (mode & S_IXGRP ? 'x' : '-'));
00511   buf[7] = mode & S_IROTH ? 'r' : '-';
00512   buf[8] = mode & S_IWOTH ? 'w' : '-';
00513   buf[9] = (mode & S_ISVTX
00514             ? (mode & S_IXOTH ? 't' : 'T')
00515             : (mode & S_IXOTH ? 'x' : '-'));
00516   buf[10] = '\0';
00517 
00518   return buf;
00519 }

int get_gid_name ( gid_t  gid,
char **  name 
)

Given a system gid get the group name as a string.

Parameters:
[in] gid The gid whose name is to be looked up.
[out] name Pointer where to receive name, must call free()
Returns:
Error code
Returns SUCCESS (0) if successful, non-zero error code otherwise.

Definition at line 576 of file util.c.

Referenced by path_info_string().

00577 {
00578     struct group gr;
00579     struct group *result;
00580     char *buf;
00581     size_t bufsize;
00582     int error;
00583 
00584     *name = NULL;
00585     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
00586     if (bufsize == -1)          /* Value was indeterminate */
00587         bufsize = 16384;        /* Should be more than enough */
00588 
00589     if ((buf = malloc(bufsize)) == NULL) {
00590         error = errno;
00591         log_msg(LOG_ERROR, "Failed getting gid name for %d, could not alloc buffer for getgrgid_r (%s)", gid, strerror(error));
00592         *name = NULL;
00593         return error;
00594     }
00595 
00596     error = getgrgid_r(gid, &gr, buf, bufsize, &result);
00597     if (result == NULL) {
00598         if (error == 0) {
00599             error = UTIL_ERROR_NOT_FOUND;
00600             log_msg(LOG_INFO, "gid name for %d was not found (%s)", gid, strerror(error));
00601         } else {
00602             log_msg(LOG_ERROR, "getgrgid_r() failed, gid = %d: (%s)", gid, strerror(error));
00603         }
00604         *name = strdup(_("unknown"));
00605         free(buf);
00606         return error;
00607     } else {
00608         *name = strdup(gr.gr_name);
00609     }
00610 
00611     free(buf);
00612     return SUCCESS;
00613 }

int get_uid_name ( uid_t  uid,
char **  name 
)

Given a system uid get the user name as a string.

Parameters:
[in] uid The uid whose name is to be looked up.
[out] name Pointer where to receive name, must call free()
Returns:
Error code
Returns SUCCESS (0) if successful, non-zero error code otherwise.

Definition at line 529 of file util.c.

Referenced by path_info_string().

00530 {
00531     struct passwd pw;
00532     struct passwd *result;
00533     char *buf;
00534     size_t bufsize;
00535     int error;
00536 
00537     *name = NULL;
00538     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
00539     if (bufsize == -1)          /* Value was indeterminate */
00540         bufsize = 16384;        /* Should be more than enough */
00541 
00542     if ((buf = malloc(bufsize)) == NULL) {
00543         error = errno;
00544         log_msg(LOG_ERROR, "Failed getting uid name for %d, could not alloc buffer for getpwuid_r (%s)", uid, strerror(error));
00545         *name = NULL;
00546         return error;
00547     }
00548 
00549     error = getpwuid_r(uid, &pw, buf, bufsize, &result);
00550     if (result == NULL) {
00551         if (error == 0) {
00552             error = UTIL_ERROR_NOT_FOUND;
00553             log_msg(LOG_INFO, "uid name for %d was not found (%s)", uid, strerror(error));
00554         } else {
00555             log_msg(LOG_ERROR, "getpwuid_r() failed, uid = %d: (%s)", uid, strerror(error));
00556         }
00557         *name = strdup(_("unknown"));
00558         free(buf);
00559         return error;
00560     } else {
00561         *name = strdup(pw.pw_name);
00562     }
00563 
00564     free(buf);
00565     return SUCCESS;
00566 }

int key_string_cmp ( const void *  _a,
const void *  _b 
)

Callback used by qsort() to compare two hash keys.

The two parameters are coerced to pointers to hash_key_t structs. If the key is not a string it is converted to a string. Then the two key strings are compared and the result returned. The primary use of this function is to produce a sorted list of hash keys.

Definition at line 92 of file util.c.

Referenced by keys_string().

00093 {
00094     const hash_key_t *a = _a, *b = _b;
00095     char buf_a[128], buf_b[128];
00096     const char *str_a, *str_b;
00097 
00098     switch(a->type) {
00099     case HASH_KEY_STRING:
00100         str_a = a->str;
00101         break;
00102     case HASH_KEY_ULONG:
00103         snprintf(buf_a, sizeof(buf_a), "%lu", a->ul);
00104         str_a = buf_a;
00105         break;
00106     default:
00107         buf_a[0] = 0;
00108         str_a = buf_a;
00109     }
00110 
00111     switch(b->type) {
00112     case HASH_KEY_STRING:
00113         str_b = b->str;
00114         break;
00115     case HASH_KEY_ULONG:
00116         snprintf(buf_b, sizeof(buf_b), "%lu", b->ul);
00117         str_b = buf_b;
00118         break;
00119     default:
00120         buf_b[0] = 0;
00121         str_b = buf_b;
00122     }
00123 
00124     return strcmp(str_a, str_b);
00125 }

char* keys_string ( hash_table_t *  table,
const char *  prefix,
const char *  suffix 
)

Generate a string with the keys of a hash table in sorted order.

Parameters:
[in] table The hash table to format
[in] prefix The string inserted before each key. May be NULL.
[in] suffix The string appended after each key. May be NULL.
Returns:
Pointer to a string which must be freed by the caller.

Definition at line 178 of file util.c.

Referenced by log_target_table(), and path_watch_string().

00179 {
00180     int prefix_len, suffix_len, extra_len;
00181     hash_key_t *keys, *key;
00182     int error;
00183     unsigned long i, count;
00184     int alloc_len;
00185     char tmp_buf[128];
00186     char *buf, *p, *buf_end;
00187 
00188     /*
00189      * Compute how many extra chars we'll need for each key after adding the
00190      * prefix and suffix.
00191      */
00192     prefix_len = prefix ? strlen(prefix) : 0;
00193     suffix_len = suffix ? strlen(suffix) : 0;
00194     extra_len = prefix_len + suffix_len;
00195 
00196     /* Get a list of keys in the table and a count of how many there are */
00197     if ((error = hash_keys(table, &count, &keys)) != HASH_SUCCESS) {
00198         log_msg(LOG_ERROR, _("could not get key array (%s)\n"),  error_string(error));
00199         return NULL;
00200     }
00201 
00202     /* Special case, if the table is empty return the empty string */
00203     if (count == 0) {
00204         return strdup("");
00205     }
00206 
00207     /* Sort the list of keys */
00208     qsort(keys, count, sizeof(hash_key_t), key_string_cmp);
00209 
00210     /* Iterate over the list and compute the maximum size of the resulting string */
00211     alloc_len = 0;
00212     for (i = 0; i < count; i++) {
00213         key = &keys[i];
00214         switch(key->type) {
00215         case HASH_KEY_STRING:
00216             alloc_len += strlen(key->str) + extra_len;
00217             break;
00218         case HASH_KEY_ULONG:
00219             snprintf(tmp_buf, sizeof(tmp_buf), "%lu", key->ul);
00220             alloc_len += strlen(tmp_buf) + extra_len;
00221             break;
00222         }
00223     }
00224 
00225     /* Allocate the return string and set up some pointers */
00226     alloc_len += 1;             /* +1 for NULL terminator */
00227     if ((buf = malloc(alloc_len)) == NULL) {
00228         free(keys);
00229         return NULL;
00230     }
00231     p = buf;                    /* current position in buffer */
00232     buf_end = &buf[alloc_len];  /* non-inclusive end of buffer */
00233 
00234     /* Iterate over the keys appending the prefix, key, and suffix for each key */
00235     for (i = 0; i < count; i++) {
00236         key = &keys[i];
00237         switch(key->type) {
00238         case HASH_KEY_STRING:
00239             p += snprintf(p, buf_end - p, "%s%s%s", prefix?prefix:"", key->str, suffix?suffix:"");
00240             if (p >= buf_end) goto fail; /* should never happen */
00241             break;
00242         case HASH_KEY_ULONG:
00243             p += snprintf(p, buf_end - p, "%s%lu%s", prefix?prefix:"", key->ul, suffix?suffix:"");
00244             if (p >= buf_end) goto fail; /* should never happen */
00245             break;
00246         }
00247     }
00248     /* Delete the final suffix */
00249     if (p > buf) p[-suffix_len] = 0;
00250     free(keys);
00251     return buf;
00252  fail:
00253     /* exhausted the buffer; NULL terminate then return truncated string */
00254     buf_end[-1] = 0;   /* should already be NULL terminated, but be safe */
00255     free(keys);
00256     return buf;
00257 
00258 }

const char* lwatch_error_string ( int  error  ) 

Return a static string describing the error code for lwatch.

Parameters:
[in] error The error code
Returns:
Pointer to thread local static string describing the error code.
Note: IS_LWATCH_ERROR(error) should true otherwise the error code is outside the set of values this function knows about. If the error code is not recognized the string "unknown(XXX)" will be returned instead where XXX is the decimal representation of the error code.

Definition at line 392 of file util.c.

Referenced by error_string().

00393 {
00394     static __thread char buf[80]; /* thread local static buffer */
00395 
00396     switch(error) {
00397     case LWATCH_ERROR_CANNOT_MONITOR:        return _("cannot monitor target");
00398     case LWATCH_ERROR_CANNOT_FIND_PATH_INFO: return _("cannot find path info");
00399     case LWATCH_ERROR_LOST_RENAME:           return _("one of the paths for a rename event is unknown");
00400     case LWATCH_ERROR_STAT_NOT_VALID:        return _("stat information is not valid");
00401     default:
00402         snprintf(buf, sizeof(buf), _("unknown(%d)"), error);
00403         return buf;
00404     }
00405 }

int strip_whitespace ( char *  str  ) 

Strip leading and trailing whitespace.

Works in place on supplied string.

Definition at line 340 of file util.c.

00341 {
00342     char *p = str;
00343 
00344     /* Find first non-space char, if not at beginning of string shift string left */
00345     for (p = str; *p && isspace(*p); p++);
00346     if (p != str) memmove(str, p, strlen(p) + 1);
00347 
00348     /* Goto end of string, working backward replace each space char with NULL */
00349     for (p = str; *p; p++);
00350     for (p--; p >= str; p--) {
00351         if (isspace(*p))
00352             *p = 0;
00353         else
00354             break;
00355     }
00356     return SUCCESS;
00357 }

const char* time_string ( time_t  t,
bool  local,
const char *  fmt 
)

Format a time_t value as a string, either in local time or UTC.

Parameters:
[in] t the time_t value in the UTC time zone to be formatted.
[in] local If true the formatted string will be in local time, otherwise the string will be be in UTC (i.e. the zone offset will be zero).
[in] fmt Optional strftime format string, if NULL format according to ISO 8601
Returns:
Pointer to a thread local static time string.
time_string(t, true, NULL) is the standard way to format time values, it will produce an ISO 8601 formatted string which preserves the local offset. The 8601 string in local time is trivially convertable to UTC during subsequent parsing, there is no loss of information (other than the zone info which was used to set the systems UTC offset). For timestamps the suggested calling parameters will yield the ideal timestamp format.

Definition at line 451 of file util.c.

Referenced by log_msg1(), and path_info_string().

00452 {
00453     static __thread char buf[128]; /* thread local static buffer */
00454     struct tm tm_time;
00455 
00456     if (local)
00457         localtime_r(&t, &tm_time);
00458     else
00459         gmtime_r(&t, &tm_time);
00460 
00461     if (!fmt) {
00462         if (local) {
00463             fmt = "%FT%T%z";
00464         } else {
00465             fmt = "%FT%TZ";
00466         }
00467     }
00468     strftime(buf, sizeof(buf), fmt, &tm_time);
00469     return buf;
00470 }

const char* util_error_string ( int  error  ) 

Return a static string describing the error code for util errors.

Parameters:
[in] error The error code
Returns:
Pointer to thread local static string describing the error code.
Note: IS_UTIL_ERROR(error) code should true otherwise the error code is outside the set of values this function knows about. If the error code is not recognized the string "unknown(XXX)" will be returned instead where XXX is the decimal representation of the error code.

Definition at line 369 of file util.c.

00370 {
00371     static __thread char buf[80]; /* thread local static buffer */
00372 
00373     switch(error) {
00374     case SUCCESS:                       return _("Success");
00375     case UTIL_ERROR_NOT_FOUND:          return _("Not found");
00376     default:
00377         snprintf(buf, sizeof(buf), _("unknown(%d)"), error);
00378         return buf;
00379     }
00380 }

char* watch_path_table_string ( hash_table_t *  table  ) 

Pretty print the contents of the watch_path_table.

Parameters:
[in] table The table to serialize into a string
Returns:
A string with the table contents, caller must free this string.
The watch_path_table contains a set of path_watch_t structures indexed by pathname. Generate a list of the table contents, sort the list by pathname, then iterate over each associated path_watch_t structure, pretty print it and append it to the total string. Return the resulting string.

Definition at line 270 of file util.c.

Referenced by log_watch_path_table().

00271 {
00272     int error;
00273     hash_entry_t *entries;
00274     unsigned long i, count;
00275     struct path_watch_t *pw;
00276     char *pw_string;
00277     char *tbl_string;
00278     size_t alloc_len, alloc_increment;
00279     size_t pw_string_len, tbl_string_len, needed_len;
00280 
00281     alloc_increment = 1024;
00282     tbl_string_len = 0;
00283 
00284     if ((tbl_string = malloc(alloc_len = alloc_increment)) == NULL) {
00285         return NULL;
00286     }
00287     *tbl_string = 0;
00288 
00289     /* Get a list of entries in the table */
00290     if ((error = hash_entries(table, &count, &entries)) != HASH_SUCCESS) {
00291         log_msg(LOG_ERROR, _("could not get entry array (%s)\n"),  error_string(error));
00292         return NULL;
00293     }
00294 
00295     /* Sort the list by pathname */
00296     qsort(entries, count, sizeof(hash_entry_t), entry_string_cmp);
00297 
00298     /* Iterate over the list */
00299     for (i = 0; i < count; i++) {
00300         /* Get the path_watch_t struct and format it */
00301         pw = (struct path_watch_t *) entries[i].value.ptr;
00302         if ((pw_string = path_watch_string(pw)) == NULL) {
00303             free(entries);
00304             return NULL;
00305         }
00306         /* Make sure we've got enough room to append the formatted path_watch_t string plus a newline */
00307         pw_string_len = strlen(pw_string);
00308         needed_len = pw_string_len + 1; /* for newline or NULL */
00309         if (tbl_string_len + needed_len > alloc_len) {
00310             alloc_len = alloc_len + MAX(needed_len,alloc_increment);
00311             if ((tbl_string = realloc(tbl_string, alloc_len)) == NULL) {
00312                 free(tbl_string);
00313                 free(entries);
00314                 return NULL;
00315             }
00316         }
00317         /* Append the formatted path_watch_t string, we know there is sufficient room in the destination */
00318         strncpy(tbl_string + tbl_string_len, pw_string, alloc_len - tbl_string_len);
00319         tbl_string_len += pw_string_len;
00320 
00321         /* We're done with the formatted entry having just copied, so we can free it now */
00322         free(pw_string);
00323 
00324         /* Append a newline, we know there is sufficient room in the destination */
00325         strncpy(tbl_string + tbl_string_len, "\n", alloc_len - tbl_string_len);
00326         tbl_string_len += 1;
00327     }
00328     /* We're done with the list of entries */
00329     free(entries);
00330 
00331     /* Replace the last newline with a NULL terminator */
00332     if (tbl_string_len > 0) tbl_string[tbl_string_len - 1] = 0;
00333     return tbl_string;
00334 }


Variable Documentation

int debug = 0

Global integer value used to indicate debugging level.

The primary use of this variable is to prevent executing code used to generate debug information if that information is not going to be used. It's an efficiency optimization.

The larger the value the more verbose debug output should be. Zero indicates no debug information should be generated.

Definition at line 66 of file util.c.

Referenced by log_set_level(), process_event(), track_path_watch(), and untrack_path_watch().


Generated on Mon Aug 31 10:06:21 2009 by  doxygen 1.5.8