#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. |
Definition in file util.c.
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.
[in] | error | The error code |
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.
[in] | mode | The file mode flags to be formatted. |
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.
[in] | gid | The gid whose name is to be looked up. |
[out] | name | Pointer where to receive name, must call free() |
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.
[in] | uid | The uid whose name is to be looked up. |
[out] | name | Pointer where to receive name, must call free() |
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.
[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. |
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.
[in] | error | 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.
[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 |
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.
[in] | error | 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.
[in] | table | The table to serialize into a 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 }
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().