added memory tracking

This commit is contained in:
Axel Kittenberger 2010-08-04 14:20:28 +00:00
parent 8aa0cba99e
commit 4efa89d951
2 changed files with 245 additions and 64 deletions

307
lsyncd.c
View File

@ -39,6 +39,11 @@
#include <libxml/tree.h> #include <libxml/tree.h>
#endif #endif
/**
* Define for debug memchecking.
*/
//#define MEMCHECK
/** /**
* Number of inotifies to read max. at once from the kernel. * Number of inotifies to read max. at once from the kernel.
*/ */
@ -384,31 +389,45 @@ struct delay_vector {
char * exclude_dirs[MAX_EXCLUDES] = {NULL, }; char * exclude_dirs[MAX_EXCLUDES] = {NULL, };
int exclude_dir_n = 0; int exclude_dir_n = 0;
/*--------------------------------------------------------------------------*
* MEMCHECK
*--------------------------------------------------------------------------*/
/** /**
* (Re)sets global options to default values. * This routines keep track which memory allocs
* * have not been freed. Debugging purposes.
* TODO memfree's
*/ */
void #ifdef MEMCHECK
reset_options(struct global_options *opts) { #include <search.h>
opts->log.loglevel = NORMAL; int memc = 0;
opts->log.flag_nodaemon = 0; void * mroot = NULL;
opts->log.logfile = NULL; struct mentry {
const void *data;
opts->flag_dryrun = 0; const char *desc;
opts->flag_stubborn = 0;
opts->flag_nostartup = 0;
opts->pidfile = NULL;
#ifdef XML_CONFIG
opts->conf_filename = DEFAULT_CONF_FILENAME;
#endif
opts->default_binary = DEFAULT_BINARY;
opts->default_exclude_file = NULL;
opts->default_callopts = standard_callopts;
opts->delay = 5;
opts->dir_confs = NULL;
opts->dir_conf_n = 0;
}; };
int mcompare(const void *pa, const void *pb) {
const struct mentry *ma = (const struct mentry *) pa;
const struct mentry *mb = (const struct mentry *) pb;
if (ma->data < mb->data) {
return -1;
}
if (ma->data > mb->data) {
return 1;
}
return 0;
}
void maction(const void *nodep, const VISIT which, const int depth) {
if (which == leaf || which == postorder) {
struct mentry * r = *((struct mentry **) nodep);
memc--;
fprintf(stderr, "<*> unfreed data %p:%s\n", r->data, r->desc);
}
}
#endif
#ifndef MEMCHECK
#define s_free(x) free(x)
#endif
/*--------------------------------------------------------------------------* /*--------------------------------------------------------------------------*
* Small generic helper routines. * Small generic helper routines.
@ -562,7 +581,7 @@ printlogf(const struct log *log, int level, const char *fmt, ...)
* available. * available.
*/ */
void * void *
s_malloc(const struct log *log, size_t size) s_malloc(const struct log *log, size_t size, const char *desc)
{ {
void *r = malloc(size); void *r = malloc(size);
@ -571,6 +590,20 @@ s_malloc(const struct log *log, size_t size)
terminate(log, LSYNCD_OUTOFMEMORY); terminate(log, LSYNCD_OUTOFMEMORY);
} }
#ifdef MEMCHECK
{
struct mentry * mentry;
memc++;
mentry = malloc(sizeof(struct mentry));
mentry->data = r;
mentry->desc = desc;
if (!mentry) {
printlogf(log, ERROR, "Out of memory in memcheck!");
terminate(log, LSYNCD_OUTOFMEMORY);
}
tsearch(mentry, &mroot, mcompare);
}
#endif
return r; return r;
} }
@ -578,7 +611,7 @@ s_malloc(const struct log *log, size_t size)
* "secured" calloc. * "secured" calloc.
*/ */
void * void *
s_calloc(const struct log *log, size_t nmemb, size_t size) s_calloc(const struct log *log, size_t nmemb, size_t size, const char *desc)
{ {
void *r = calloc(nmemb, size); void *r = calloc(nmemb, size);
@ -587,6 +620,21 @@ s_calloc(const struct log *log, size_t nmemb, size_t size)
terminate(log, LSYNCD_OUTOFMEMORY); terminate(log, LSYNCD_OUTOFMEMORY);
} }
#ifdef MEMCHECK
{
struct mentry * mentry;
memc++;
mentry = malloc(sizeof(struct mentry));
mentry->data = r;
mentry->desc = desc;
if (!mentry) {
printlogf(log, ERROR, "Out of memory in memcheck!");
terminate(log, LSYNCD_OUTOFMEMORY);
}
tsearch(mentry, &mroot, mcompare);
}
#endif
return r; return r;
} }
@ -603,6 +651,33 @@ s_realloc(const struct log *log, void *ptr, size_t size)
terminate(log, LSYNCD_OUTOFMEMORY); terminate(log, LSYNCD_OUTOFMEMORY);
} }
#ifdef MEMCHECK
{
struct mentry * mentry = malloc(sizeof(struct mentry));
struct mentry **ret;
if (!mentry) {
printlogf(log, ERROR, "Out of memory in memcheck!");
terminate(log, LSYNCD_OUTOFMEMORY);
}
if (ptr == NULL) {
fprintf(stderr, "<*> Reallocating NULL!?\n");
return r;
}
// first delete the old entry
mentry->data = ptr;
ret = tfind(mentry, &mroot, mcompare);
if (ret == NULL) {
fprintf(stderr, "<*> Memcheck error, reallocating unknown pointer %p!\n", ptr);
return r;
}
mentry->desc = (*ret)->desc;
tdelete(mentry, &mroot, mcompare);
// and reenter the reallocated entry
mentry->data = r;
tsearch(mentry, &mroot, mcompare);
}
#endif
return r; return r;
} }
@ -610,7 +685,7 @@ s_realloc(const struct log *log, void *ptr, size_t size)
* "secured" strdup. * "secured" strdup.
*/ */
char * char *
s_strdup(const struct log *log, const char *src) s_strdup(const struct log *log, const char *src, const char *desc)
{ {
char *s = strdup(src); char *s = strdup(src);
@ -619,9 +694,44 @@ s_strdup(const struct log *log, const char *src)
terminate(log, LSYNCD_OUTOFMEMORY); terminate(log, LSYNCD_OUTOFMEMORY);
} }
#ifdef MEMCHECK
{
struct mentry * mentry;
memc++;
mentry = malloc(sizeof(struct mentry));
mentry->data = s;
mentry->desc = desc;
if (!mentry) {
printlogf(log, ERROR, "Out of memory in memcheck!");
terminate(log, LSYNCD_OUTOFMEMORY);
}
tsearch(mentry, &mroot, mcompare);
}
#endif
return s; return s;
} }
#ifdef MEMCHECK
void
s_free(void *p) {
struct mentry mentry = {0,};
struct mentry **r;
memc--;
if (p == NULL) {
fprintf(stderr, "<*> Memcheck freeing NULL!\n");
return;
}
mentry.data = p;
r = tdelete(&mentry, &mroot, mcompare);
if (r == NULL) {
fprintf(stderr, "<*> Memcheck error, freeing unknown pointer %p!\n", p);
}
free(p);
}
#endif
/** /**
* Returns the canonicalized path of a directory with a final '/'. * Returns the canonicalized path of a directory with a final '/'.
* Makes sure it is a directory. * Makes sure it is a directory.
@ -629,7 +739,7 @@ s_strdup(const struct log *log, const char *src)
char * char *
realdir(const struct log *log, const char *dir) realdir(const struct log *log, const char *dir)
{ {
char* cs = s_malloc(log, PATH_MAX+1); char* cs = s_malloc(log, PATH_MAX+1, "realdir/cs");
cs = realpath(dir, cs); cs = realpath(dir, cs);
if (cs == NULL) { if (cs == NULL) {
@ -644,7 +754,7 @@ realdir(const struct log *log, const char *dir)
struct stat st; struct stat st;
stat(cs, &st); stat(cs, &st);
if (!S_ISDIR(st.st_mode)) { if (!S_ISDIR(st.st_mode)) {
free(cs); s_free(cs);
return NULL; return NULL;
} }
@ -652,6 +762,58 @@ realdir(const struct log *log, const char *dir)
return cs; return cs;
} }
/*--------------------------------------------------------------------------*
* Options.
*--------------------------------------------------------------------------*/
/**
* (Re)sets global options to default values.
*
* TODO memfree's
*/
void
reset_options(struct global_options *opts) {
opts->log.loglevel = NORMAL;
opts->log.flag_nodaemon = 0;
if (opts->log.logfile) {
s_free(opts->log.logfile);
opts->log.logfile = NULL;
}
opts->flag_dryrun = 0;
opts->flag_stubborn = 0;
opts->flag_nostartup = 0;
if (opts->pidfile) {
s_free(opts->pidfile);
opts->pidfile = NULL;
}
#ifdef XML_CONFIG
if (opts->conf_filename && opts->conf_filename != DEFAULT_CONF_FILENAME) {
s_free(opts->conf_filename);
}
opts->conf_filename = DEFAULT_CONF_FILENAME;
#endif
if (opts->default_binary && opts->default_binary != DEFAULT_BINARY) {
s_free(opts->default_binary);
}
opts->default_binary = DEFAULT_BINARY;
if (opts->default_exclude_file) {
s_free(opts->default_exclude_file);
opts->default_exclude_file = NULL;
}
// TODO free callopts
opts->default_callopts = standard_callopts;
opts->delay = 5;
opts->dir_confs = NULL;
opts->dir_conf_n = 0;
};
/*--------------------------------------------------------------------------* /*--------------------------------------------------------------------------*
* Per directory configuration handling. * Per directory configuration handling.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
@ -675,14 +837,14 @@ new_dir_conf(struct global_options *opts) {
opts->dir_confs = s_realloc(log, opts->dir_confs, opts->dir_conf_n * sizeof(struct dir_conf)); opts->dir_confs = s_realloc(log, opts->dir_confs, opts->dir_conf_n * sizeof(struct dir_conf));
memset(opts->dir_confs + opts->dir_conf_n - 1, 0, sizeof(struct dir_conf)); memset(opts->dir_confs + opts->dir_conf_n - 1, 0, sizeof(struct dir_conf));
// creates targets NULL terminator (no targets yet) // creates targets NULL terminator (no targets yet)
opts->dir_confs[opts->dir_conf_n - 1].targets = s_calloc(log, 1, sizeof(char *)); opts->dir_confs[opts->dir_conf_n - 1].targets = s_calloc(log, 1, sizeof(char *), "dir_conf");
return opts->dir_confs + opts->dir_conf_n - 1; return opts->dir_confs + opts->dir_conf_n - 1;
} else { } else {
// create the memory. // create the memory.
opts->dir_conf_n = 1; opts->dir_conf_n = 1;
opts->dir_confs = s_calloc(log, opts->dir_conf_n, sizeof(struct dir_conf)); opts->dir_confs = s_calloc(log, opts->dir_conf_n, sizeof(struct dir_conf), "dir_conf");
// creates targets NULL terminator (no targets yet) // creates targets NULL terminator (no targets yet)
opts->dir_confs[0].targets = s_calloc(log, 1, sizeof(char *)); opts->dir_confs[0].targets = s_calloc(log, 1, sizeof(char *), "dir_conf-target");
return opts->dir_confs; return opts->dir_confs;
} }
} }
@ -706,7 +868,7 @@ dir_conf_add_target(const struct log *log, struct dir_conf *dir_conf, char *targ
} }
dir_conf->targets = s_realloc(log, dir_conf->targets, (target_n + 2) * sizeof(char *)); dir_conf->targets = s_realloc(log, dir_conf->targets, (target_n + 2) * sizeof(char *));
dir_conf->targets[target_n] = s_strdup(log, target); dir_conf->targets[target_n] = s_strdup(log, target, "dupped target");
dir_conf->targets[target_n + 1] = NULL; dir_conf->targets[target_n + 1] = NULL;
} }
@ -776,7 +938,7 @@ remove_first_delay(struct delay_vector *delays)
char * char *
parse_option_text(const struct log *log, char *text, bool recursive) parse_option_text(const struct log *log, char *text, bool recursive)
{ {
char * str = s_strdup(log, text); char * str = s_strdup(log, text, "dupped option text");
char * chr; // search result for %. char * chr; // search result for %.
// replace all '%' specifiers with there special meanings // replace all '%' specifiers with there special meanings
@ -818,7 +980,7 @@ get_arg_str(const struct log *log, char **argv, int argc) {
} }
// alloc // alloc
str = s_malloc(log, len + 2 * argc + 1); str = s_malloc(log, len + 2 * argc + 1, "argument string");
str[0] = 0; str[0] = 0;
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
@ -861,7 +1023,7 @@ action(const struct global_options *opts,
// makes a copy of all call parameters // makes a copy of all call parameters
// step 1 binary itself // step 1 binary itself
argv[argc++] = s_strdup(log, dir_conf->binary ? dir_conf->binary : opts->default_binary); argv[argc++] = s_strdup(log, dir_conf->binary ? dir_conf->binary : opts->default_binary, "argv");
// now all other parameters // now all other parameters
for(; optp->kind != CO_EOL; optp++) { for(; optp->kind != CO_EOL; optp++) {
switch (optp->kind) { switch (optp->kind) {
@ -874,14 +1036,14 @@ action(const struct global_options *opts,
if (dir_conf->exclude_file == NULL && opts->default_exclude_file == NULL) { if (dir_conf->exclude_file == NULL && opts->default_exclude_file == NULL) {
continue; continue;
} }
argv[argc++] = s_strdup(log, "--exclude-from"); argv[argc++] = s_strdup(log, "--exclude-from", "argv exclude-from");
argv[argc++] = s_strdup(log, dir_conf->exclude_file ? dir_conf->exclude_file : opts->default_exclude_file); argv[argc++] = s_strdup(log, dir_conf->exclude_file ? dir_conf->exclude_file : opts->default_exclude_file, "argv exclude-file");
continue; continue;
case CO_SOURCE : case CO_SOURCE :
argv[argc++] = s_strdup(log, src); argv[argc++] = s_strdup(log, src, "argv source");
continue; continue;
case CO_DEST : case CO_DEST :
argv[argc++] = s_strdup(log, dest); argv[argc++] = s_strdup(log, dest, "argv dest");
continue; continue;
default: default:
printlogf(log, ERROR, "Internal error: unknown kind of option."); printlogf(log, ERROR, "Internal error: unknown kind of option.");
@ -901,10 +1063,10 @@ action(const struct global_options *opts,
char * binary = dir_conf->binary ? dir_conf->binary : opts->default_binary; char * binary = dir_conf->binary ? dir_conf->binary : opts->default_binary;
char * argall = get_arg_str(log, argv, argc); char * argall = get_arg_str(log, argv, argc);
printlogf(log, NORMAL, "dry run: would call %s(%s)", binary, argall); printlogf(log, NORMAL, "dry run: would call %s(%s)", binary, argall);
free(argall); s_free(argall);
for (i = 0; i < argc; ++i) { for (i = 0; i < argc; ++i) {
if (argv[i]) { if (argv[i]) {
free(argv[i]); s_free(argv[i]);
} }
} }
return true; return true;
@ -932,7 +1094,7 @@ action(const struct global_options *opts,
// free the memory from the arguments. // free the memory from the arguments.
for (i = 0; i < argc; ++i) { for (i = 0; i < argc; ++i) {
if (argv[i]) { if (argv[i]) {
free(argv[i]); s_free(argv[i]);
} }
} }
@ -1010,13 +1172,13 @@ add_watch(const struct log *log,
watches->size * sizeof(struct watch *)); watches->size * sizeof(struct watch *));
} }
// allocate memory for a new watch // allocate memory for a new watch
watches->data[watches->len++] = s_calloc(log, 1, sizeof(struct watch)); watches->data[watches->len++] = s_calloc(log, 1, sizeof(struct watch), "watch");
} }
w = watches->data[wi]; w = watches->data[wi];
w->wd = wd; w->wd = wd;
w->parent = parent; w->parent = parent;
w->dirname = s_strdup(log, dirname); w->dirname = s_strdup(log, dirname, "dirname");
w->dir_conf = dir_conf; w->dir_conf = dir_conf;
w->alarm = 0; // not needed, just to be save w->alarm = 0; // not needed, just to be save
w->delayed = false; w->delayed = false;
@ -1346,7 +1508,7 @@ remove_dirwatch(const struct global_options *opts,
// mark this entry invalid // mark this entry invalid
w->wd = -1; w->wd = -1;
free(w->dirname); s_free(w->dirname);
w->dirname = NULL; w->dirname = NULL;
// remove a possible delay // remove a possible delay
@ -1451,8 +1613,6 @@ handle_event(const struct global_options *opts,
return false; return false;
} }
//TODO AXK ORDER?
// put the watch on the delay or act if delay == 0 // put the watch on the delay or act if delay == 0
if ((IN_ATTRIB | IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | if ((IN_ATTRIB | IN_CREATE | IN_CLOSE_WRITE | IN_DELETE |
IN_MOVED_TO | IN_MOVED_FROM) & event->mask IN_MOVED_TO | IN_MOVED_FROM) & event->mask
@ -1711,7 +1871,7 @@ parse_callopts(struct global_options *opts, xmlNodePtr node) {
opt_n++; opt_n++;
} }
opt_n++; opt_n++;
asw = (struct call_option *) s_calloc(NULL, opt_n, sizeof(struct call_option)); asw = (struct call_option *) s_calloc(NULL, opt_n, sizeof(struct call_option), "call options");
// fill in the answer // fill in the answer
opt_n = 0; opt_n = 0;
@ -1727,7 +1887,7 @@ parse_callopts(struct global_options *opts, xmlNodePtr node) {
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
asw[opt_n].kind = CO_TEXT; asw[opt_n].kind = CO_TEXT;
asw[opt_n].text = s_strdup(NULL, (char *) xc); asw[opt_n].text = s_strdup(NULL, (char *) xc, "asw text");
} else if (!xmlStrcmp(cnode->name, BAD_CAST "exclude-file")) { } else if (!xmlStrcmp(cnode->name, BAD_CAST "exclude-file")) {
asw[opt_n].kind = CO_EXCLUDE; asw[opt_n].kind = CO_EXCLUDE;
} else if (!xmlStrcmp(cnode->name, BAD_CAST "source")) { } else if (!xmlStrcmp(cnode->name, BAD_CAST "source")) {
@ -1767,7 +1927,7 @@ parse_directory(struct global_options *opts, xmlNodePtr node) {
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
// TODO: use realdir() on xc // TODO: use realdir() on xc
dc->source = s_strdup(NULL, (char *) xc); dc->source = s_strdup(NULL, (char *) xc, "xml source");
} else if (!xmlStrcmp(dnode->name, BAD_CAST "target")) { } else if (!xmlStrcmp(dnode->name, BAD_CAST "target")) {
xc = xmlGetProp(dnode, BAD_CAST "path"); xc = xmlGetProp(dnode, BAD_CAST "path");
if (xc == NULL) { if (xc == NULL) {
@ -1781,14 +1941,14 @@ parse_directory(struct global_options *opts, xmlNodePtr node) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <binary>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <binary>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
dc->binary = s_strdup(NULL, (char *) xc); dc->binary = s_strdup(NULL, (char *) xc, "xml binary");
} else if (!xmlStrcmp(dnode->name, BAD_CAST "exclude-from")) { } else if (!xmlStrcmp(dnode->name, BAD_CAST "exclude-from")) {
xc = xmlGetProp(dnode, BAD_CAST "filename"); xc = xmlGetProp(dnode, BAD_CAST "filename");
if (xc == NULL) { if (xc == NULL) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <exclude-from>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <exclude-from>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
dc->exclude_file = s_strdup(NULL, (char *) xc); dc->exclude_file = s_strdup(NULL, (char *) xc, "xml exclude");
} else if (!xmlStrcmp(dnode->name, BAD_CAST "callopts")) { } else if (!xmlStrcmp(dnode->name, BAD_CAST "callopts")) {
if (dc->callopts) { if (dc->callopts) {
printlogf(NULL, ERROR, "error in config file: there is more than one <callopts> in a <directory>\n"); printlogf(NULL, ERROR, "error in config file: there is more than one <callopts> in a <directory>\n");
@ -1850,28 +2010,28 @@ parse_settings(struct global_options *opts, xmlNodePtr node) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <exclude-from/>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <exclude-from/>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
opts->default_exclude_file = s_strdup(NULL, (char *) xc); opts->default_exclude_file = s_strdup(NULL, (char *) xc, "xml default-exclude-file");
} else if (!xmlStrcmp(snode->name, BAD_CAST "logfile")) { } else if (!xmlStrcmp(snode->name, BAD_CAST "logfile")) {
xc = xmlGetProp(snode, BAD_CAST "filename"); xc = xmlGetProp(snode, BAD_CAST "filename");
if (xc == NULL) { if (xc == NULL) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <logfile/>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <logfile/>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
opts->log.logfile = s_strdup(NULL, (char *) xc); opts->log.logfile = s_strdup(NULL, (char *) xc, "xml logfile");
} else if (!xmlStrcmp(snode->name, BAD_CAST "binary")) { } else if (!xmlStrcmp(snode->name, BAD_CAST "binary")) {
xc = xmlGetProp(snode, BAD_CAST "filename"); xc = xmlGetProp(snode, BAD_CAST "filename");
if (xc == NULL) { if (xc == NULL) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <binary/>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <binary/>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
opts->default_binary = s_strdup(NULL, (char *) xc); opts->default_binary = s_strdup(NULL, (char *) xc, "xml default-binary");
} else if (!xmlStrcmp(snode->name, BAD_CAST "pidfile")) { } else if (!xmlStrcmp(snode->name, BAD_CAST "pidfile")) {
xc = xmlGetProp(snode, BAD_CAST "filename"); xc = xmlGetProp(snode, BAD_CAST "filename");
if (xc == NULL) { if (xc == NULL) {
printlogf(NULL, ERROR, "error in config file: attribute filename missing from <pidfile/>\n"); printlogf(NULL, ERROR, "error in config file: attribute filename missing from <pidfile/>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE); terminate(NULL, LSYNCD_BADCONFIGFILE);
} }
opts->pidfile = s_strdup(NULL, (char *) xc); opts->pidfile = s_strdup(NULL, (char *) xc, "xml pidfile");
} else if (!xmlStrcmp(snode->name, BAD_CAST "callopts")) { } else if (!xmlStrcmp(snode->name, BAD_CAST "callopts")) {
opts->default_callopts = parse_callopts(opts, snode); opts->default_callopts = parse_callopts(opts, snode);
} else if (!xmlStrcmp(snode->name, BAD_CAST "scarce")) { } else if (!xmlStrcmp(snode->name, BAD_CAST "scarce")) {
@ -2018,7 +2178,7 @@ parse_options(struct global_options *opts, int argc, char **argv)
if (c == 0) { // longoption if (c == 0) { // longoption
if (!strcmp("conf", long_options[oi].name)) { if (!strcmp("conf", long_options[oi].name)) {
read_conf = true; read_conf = true;
opts->conf_filename = s_strdup(NULL, optarg); opts->conf_filename = s_strdup(NULL, optarg, "opt conf-filename");
} }
if (!strcmp("help", long_options[oi].name)) { if (!strcmp("help", long_options[oi].name)) {
@ -2063,7 +2223,7 @@ parse_options(struct global_options *opts, int argc, char **argv)
if (c == 0) { // longoption if (c == 0) { // longoption
if (!strcmp("binary", long_options[oi].name)) { if (!strcmp("binary", long_options[oi].name)) {
opts->default_binary = s_strdup(NULL, optarg); opts->default_binary = s_strdup(NULL, optarg, "opt default-binary");
} }
if (!strcmp("delay", long_options[oi].name)) { if (!strcmp("delay", long_options[oi].name)) {
@ -2080,7 +2240,7 @@ parse_options(struct global_options *opts, int argc, char **argv)
} }
if (!strcmp("exclude-from", long_options[oi].name)) { if (!strcmp("exclude-from", long_options[oi].name)) {
opts->default_exclude_file = s_strdup(NULL, optarg); opts->default_exclude_file = s_strdup(NULL, optarg, "opt default-exclude-file");
} }
if (!strcmp("help", long_options[oi].name)) { if (!strcmp("help", long_options[oi].name)) {
@ -2088,11 +2248,11 @@ parse_options(struct global_options *opts, int argc, char **argv)
} }
if (!strcmp("logfile", long_options[oi].name)) { if (!strcmp("logfile", long_options[oi].name)) {
opts->log.logfile = s_strdup(NULL, optarg); opts->log.logfile = s_strdup(NULL, optarg, "opt logfile");
} }
if (!strcmp("pidfile", long_options[oi].name)) { if (!strcmp("pidfile", long_options[oi].name)) {
opts->pidfile = s_strdup(NULL, optarg); opts->pidfile = s_strdup(NULL, optarg, "opt pidfile");
} }
if (!strcmp("version", long_options[oi].name)) { if (!strcmp("version", long_options[oi].name)) {
@ -2208,7 +2368,7 @@ parse_exclude_file(struct log *log, char *filename) {
printlogf(log, NORMAL, "Excluding directories of the name '%s'", line); printlogf(log, NORMAL, "Excluding directories of the name '%s'", line);
exclude_dirs[exclude_dir_n] = s_malloc(log, strlen(line) + 1); exclude_dirs[exclude_dir_n] = s_malloc(log, strlen(line) + 1, "exclude_dir");
strcpy(exclude_dirs[exclude_dir_n], line); strcpy(exclude_dirs[exclude_dir_n], line);
exclude_dir_n++; exclude_dir_n++;
} }
@ -2278,10 +2438,10 @@ main(int argc, char **argv)
} }
watches.size = VECT_INIT_SIZE; watches.size = VECT_INIT_SIZE;
watches.data = s_calloc(log, watches.size, sizeof(struct watch *)); watches.data = s_calloc(log, watches.size, sizeof(struct watch *), "watches vector");
delays.size = VECT_INIT_SIZE; delays.size = VECT_INIT_SIZE;
delays.data = s_calloc(log, delays.size, sizeof(struct watch *)); delays.data = s_calloc(log, delays.size, sizeof(struct watch *), "delays vector");
{ {
// add all watches // add all watches
@ -2334,5 +2494,26 @@ main(int argc, char **argv)
master_loop(&opts, &watches, &delays, inotify_fd); master_loop(&opts, &watches, &delays, inotify_fd);
{
// memory clean up
int i;
reset_options(&opts);
for(i = 0; i < watches.len; i++) {
if (watches.data[i]->dirname) {
s_free(watches.data[i]->dirname);
}
s_free(watches.data[i]);
}
s_free(watches.data);
s_free(delays.data);
}
#ifdef MEMCHECK
fprintf(stderr, "Memcheck count: %d\n", memc);
twalk(mroot, maction);
fprintf(stderr, "Memcheck count: %d\n", memc);
#endif
return 0; return 0;
} }

View File

@ -37,7 +37,7 @@ for A in 1 2 3 4 5 6 7 8 9 10; do
done done
echo -e "$CON* waiting for lsyncd to do the job.$COFF" echo -e "$CON* waiting for lsyncd to do the job.$COFF"
sleep 20s sleep 10s
echo -e "$CON* killing lsyncd$COFF" echo -e "$CON* killing lsyncd$COFF"
LSYNCPID=$(cat "${PIDFILE}") LSYNCPID=$(cat "${PIDFILE}")