Hello Willy, I don't receive all the mails from [email protected]. For exemple I didn't received : http://article.gmane.org/gmane.comp.web.haproxy/27795
However I am sure I sent a blank mail to [email protected] (I rechecked). Can you check on the server side ? > > I forgot to free the memory allocated at 'filename = calloc' (why > > valgrind > > didn't warn...). Forget this patch. I will send another one > > tomorow. > > Yes I noticed, and there's this one as well : > > > > + wlt = calloc(1, sizeof(*wlt)); > > > + tmp_str = strdup(filename); > > > + if (!wlt || !tmp_str) { > > > + Alert("Cannot load > > > configuration > > > files %s : out of memory.\n", > > > + filename); > > > + exit(1); > > > + } > > If tmp_str fails and wlt succeeds, wlt is not freed. If tmp_str fails and wlt succeeds we still got the Alert and everything it freed on exit. Anyway the problem isn't here anymore as I get ride of strdup. See the end of this mail. > Overall I still think that writing this into a dedicated function > will make the controls and unrolling easier. I'd suggest something > like this which is much more conventional, auditable and maintainable > : > > /* loads config file/dir <arg>, returns 0 on failure with errmsg > * filled with an error message. > */ > int load_config_file(const char *arg, char **errmsg) > { > ... > wlt = calloc(1, sizeof(*wlt)); > if (!wlt) { > memprintf(errmsg, "out of memory"); > goto fail_wlt; > } > > tmp_str = strdup(filename); > if (!tmp_str) { > memprintf(errmsg, "out of memory"); > goto fail_tmp_str; > } > ... > return 1; > ... > fail_smp_str: > free(wlt); > fail_wlt: > ... > return 0; > } > > Then in init() : > > if (!load_config_from_file(argv, &errmsg)) { > Alert("Cannot load configuration files %s : %s.\n", filename, > errmsg); > exit(1); > } I create the function "void cfgfiles_expand_directories(void)", but not the "load_config_file" one. I am not accustomed to using goto and it's hard for me to use it here as I actually don't see the point of it (in cfgfiles_expand_directories). It doesn't reduce the number of lines and, as after every alert we call exit, there is no need to clean anything. > Also, please don't use sprintf() but snprintf() as I mentionned in > the earlier mail. I used sprintf at first because the man says it's not C89 compatible : fprintf(), printf(), sprintf(), vprintf(), vfprintf(), vsprintf(): POSIX.1-2001, POSIX.1-2008, C89, C99. snprintf(), vsnprintf(): POSIX.1-2001, POSIX.1-2008, C99. and the CONTRIBUTING file says : It is important to keep in mind that certain facilities offered by recent versions must not be used in the code : - … - in general, anything which requires C99 (such as declaring variables in "for" statements) I changed it to snprintf, yet I didn't check the output as it shouldn't be able to fail (the string size == copied size == calloc size). Here is a new version of the patch. Only for the src/haproxy.c file. I will send a complete patch when everything will be settled. I also free head memory from the "wlt = calloc(1, sizeof(*wlt));" line, in the deinit function. I don't think it's necessary as deinit is followed by exit but I thought it would be cleaner as we also free cfg_cfgfiles elements. Thank you very much for all your comments ! Maxime de Roucy ##### diff --git a/src/haproxy.c b/src/haproxy.c index 0c223e5..3fae428 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -33,10 +33,12 @@ #include <ctype.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/socket.h> #include <netinet/tcp.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <dirent.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> @@ -423,7 +425,7 @@ void usage(char *name) { display_version(); fprintf(stderr, - "Usage : %s [-f <cfgfile>]* [ -vdV" + "Usage : %s [-f <cfgfile|cfgdir>]* [ -vdV" "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n" " [ -p <pidfile> ] [ -m <max megs> ] [ -C <dir> ] [-- <cfgfile>*]\n" " -v displays version ; -vv shows known build options.\n" @@ -551,6 +553,95 @@ void dump(struct sig_handler *sh) pool_gc2(); } +/* This function check if cfg_cfgfiles containes directories. + * If it find one, it add all the files (and only files) it containes + * in cfg_cfgfiles in place of the directory (and remove the directory). + * It add the files in lexical order. + */ +void cfgfiles_expand_directories(void) +{ + struct wordlist *wl, *wlb; + + list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) { + struct stat file_stat; + struct dirent **dir_entries; + int dir_entries_nb; + int dir_entries_it; + + if (stat(wl->s, &file_stat)) { + Alert("Cannot open configuration file/directory %s : %s\n", + wl->s, + strerror(errno)); + exit(1); + } + + if (!S_ISDIR(file_stat.st_mode)) + continue; + + dir_entries_nb = scandir(wl->s, &dir_entries, NULL, alphasort); + if (dir_entries_nb < 0) { + Alert("Cannot open configuration directory %s : %s\n", + wl->s, + strerror(errno)); + exit(1); + } + + for (dir_entries_it = 0; dir_entries_it < dir_entries_nb; dir_entries_it++) { + struct dirent *dir_entry = dir_entries[dir_entries_it]; + char *filename; + int filename_size = strlen(wl->s) + + 1 /* for '/' */ + + strlen(dir_entry->d_name); + + filename = calloc(filename_size + 1, sizeof(*filename)); + if (!filename) { + Alert("Cannot load configuration files %s : out of memory.\n", + filename); + exit(1); + } + + snprintf(filename, filename_size + 1, "%s/%s", wl->s, dir_entry->d_name); + + if (stat(filename, &file_stat)) { + Alert("Cannot open configuration file %s : %s\n", + wl->s, + strerror(errno)); + exit(1); + } + + /* don't add anything else than regular file in cfg_cfgfiles + * this way we avoid loops + */ + if (S_ISREG(file_stat.st_mode)) { + struct wordlist *wlt; + + wlt = calloc(1, sizeof(*wlt)); + if (!wlt) { + Alert("Cannot load configuration files %s : out of memory.\n", + filename); + exit(1); + } + + wlt->s = filename; + + /* add wlt (a file) before wl (a directory) + * in cfg_cfgfiles + */ + LIST_ADDQ(&wl->list, &wlt->list); + } + else { + free(filename); + } + free(dir_entry); + } + free(dir_entries); + + /* remove the current directory (wl) from cfg_cfgfiles */ + LIST_DEL(&wl->list); + free(wl); + } +} + /* * This function initializes all the necessary variables. It only returns * if everything is OK. If something fails, it exits. @@ -738,7 +829,7 @@ void init(int argc, char **argv) case 'f' : wl = calloc(1, sizeof(*wl)); if (!wl) { - Alert("Cannot load configuration file %s : out of memory.\n", *argv); + Alert("Cannot load configuration file/directory %s : out of memory.\n", *argv); exit(1); } wl->s = *argv; @@ -758,14 +849,17 @@ void init(int argc, char **argv) (arg_mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG)); - if (LIST_ISEMPTY(&cfg_cfgfiles)) - usage(progname); - if (change_dir && chdir(change_dir) < 0) { Alert("Could not change to directory %s : %s\n", change_dir, strerror(errno)); exit(1); } + /* handle cfgfiles that are actualy directories */ + cfgfiles_expand_directories(); + + if (LIST_ISEMPTY(&cfg_cfgfiles)) + usage(progname); + global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */ init_default_instance(); @@ -1238,7 +1332,7 @@ static void deinit_stick_rules(struct list *rules) } } -void deinit(void) +void deinit(int argc, char **argv) { struct proxy *p = proxy, *p0; struct cap_hdr *h,*h_next; @@ -1550,6 +1644,20 @@ void deinit(void) free(log); } list_for_each_entry_safe(wl, wlb, &cfg_cfgfiles, list) { + int argc_i = argc - 1; + char **argv_i = argv + 1; + int is_arg = 0; + + while (argc_i > 0) { + if (*argv_i == wl->s) + is_arg = 1; + argv_i++; + argc_i--; + } + + if (!is_arg) + free(wl->s); + LIST_DEL(&wl->list); free(wl); } @@ -1952,7 +2060,7 @@ int main(int argc, char **argv) run_poll_loop(); /* Do some cleanup */ - deinit(); + deinit(argc, argv); exit(0); } -- 2.8.2
signature.asc
Description: This is a digitally signed message part

