00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #define _GNU_SOURCE
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <stdarg.h>
00018 #include <stdint.h>
00019 #include <unistd.h>
00020 #include <string.h>
00021 #include <ctype.h>
00022 #include <errno.h>
00023 #include <pwd.h>
00024 #include <grp.h>
00025
00026 #include <sys/param.h>
00027 #include <sys/stat.h>
00028
00029 #include "dhash.h"
00030 #include "util.h"
00031 #include "path_utils.h"
00032 #include "logging.h"
00033 #include "inotify_watch.h"
00034 #include "watch_database.h"
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 int debug = 0;
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 int key_string_cmp(const void *_a, const void *_b)
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 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 int entry_string_cmp(const void *_a, const void *_b)
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 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 char *keys_string(hash_table_t *table, const char *prefix, const char *suffix)
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
00190
00191
00192 prefix_len = prefix ? strlen(prefix) : 0;
00193 suffix_len = suffix ? strlen(suffix) : 0;
00194 extra_len = prefix_len + suffix_len;
00195
00196
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
00203 if (count == 0) {
00204 return strdup("");
00205 }
00206
00207
00208 qsort(keys, count, sizeof(hash_key_t), key_string_cmp);
00209
00210
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
00226 alloc_len += 1;
00227 if ((buf = malloc(alloc_len)) == NULL) {
00228 free(keys);
00229 return NULL;
00230 }
00231 p = buf;
00232 buf_end = &buf[alloc_len];
00233
00234
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;
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;
00245 break;
00246 }
00247 }
00248
00249 if (p > buf) p[-suffix_len] = 0;
00250 free(keys);
00251 return buf;
00252 fail:
00253
00254 buf_end[-1] = 0;
00255 free(keys);
00256 return buf;
00257
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 char *watch_path_table_string(hash_table_t *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
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
00296 qsort(entries, count, sizeof(hash_entry_t), entry_string_cmp);
00297
00298
00299 for (i = 0; i < count; i++) {
00300
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
00307 pw_string_len = strlen(pw_string);
00308 needed_len = pw_string_len + 1;
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
00318 strncpy(tbl_string + tbl_string_len, pw_string, alloc_len - tbl_string_len);
00319 tbl_string_len += pw_string_len;
00320
00321
00322 free(pw_string);
00323
00324
00325 strncpy(tbl_string + tbl_string_len, "\n", alloc_len - tbl_string_len);
00326 tbl_string_len += 1;
00327 }
00328
00329 free(entries);
00330
00331
00332 if (tbl_string_len > 0) tbl_string[tbl_string_len - 1] = 0;
00333 return tbl_string;
00334 }
00335
00336
00337
00338
00339
00340 int strip_whitespace(char *str)
00341 {
00342 char *p = str;
00343
00344
00345 for (p = str; *p && isspace(*p); p++);
00346 if (p != str) memmove(str, p, strlen(p) + 1);
00347
00348
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 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 const char *util_error_string(int error)
00370 {
00371 static __thread char buf[80];
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 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 const char *lwatch_error_string(int error)
00393 {
00394 static __thread char buf[80];
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 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 const char *error_string(int error)
00418 {
00419 static __thread char buf[256];
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 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 const char *time_string(time_t t, bool local, const char *fmt)
00452 {
00453 static __thread char buf[128];
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 }
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 const char *file_mode_string(mode_t mode)
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 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 int get_uid_name(uid_t uid, char **name)
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)
00540 bufsize = 16384;
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 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 int get_gid_name(gid_t gid, char **name)
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)
00587 bufsize = 16384;
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 }
00614
00615