Lines 77-372
Link Here
|
77 |
|
77 |
|
78 |
extern void yyrestart(FILE *); |
78 |
extern void yyrestart(FILE *); |
79 |
|
79 |
|
80 |
static int |
80 |
static int isitme(const char *name); |
81 |
isitme(const char *name) |
81 |
static bool family_supported(int family); |
82 |
{ |
82 |
static int node_names(char **namesp); |
83 |
char buf[MAXHOSTNAMELEN]; |
|
|
84 |
char *pos; |
85 |
size_t bufsize; |
86 |
|
87 |
/* |
88 |
* First check if the given name matches our full hostname. |
89 |
*/ |
90 |
if (gethostname(buf, sizeof(buf)) < 0) { |
91 |
pjdlog_errno(LOG_ERR, "gethostname() failed"); |
92 |
return (-1); |
93 |
} |
94 |
if (strcmp(buf, name) == 0) |
95 |
return (1); |
96 |
|
97 |
/* |
98 |
* Now check if it matches first part of the host name. |
99 |
*/ |
100 |
pos = strchr(buf, '.'); |
101 |
if (pos != NULL && (size_t)(pos - buf) == strlen(name) && |
102 |
strncmp(buf, name, pos - buf) == 0) { |
103 |
return (1); |
104 |
} |
105 |
|
106 |
/* |
107 |
* At the end check if name is equal to our host's UUID. |
108 |
*/ |
109 |
bufsize = sizeof(buf); |
110 |
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { |
111 |
pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); |
112 |
return (-1); |
113 |
} |
114 |
if (strcasecmp(buf, name) == 0) |
115 |
return (1); |
116 |
|
117 |
/* |
118 |
* Looks like this isn't about us. |
119 |
*/ |
120 |
return (0); |
121 |
} |
122 |
|
123 |
static bool |
124 |
family_supported(int family) |
125 |
{ |
126 |
int sock; |
127 |
|
128 |
sock = socket(family, SOCK_STREAM, 0); |
129 |
if (sock == -1 && errno == EPROTONOSUPPORT) |
130 |
return (false); |
131 |
if (sock >= 0) |
132 |
(void)close(sock); |
133 |
return (true); |
134 |
} |
135 |
|
136 |
static int |
137 |
node_names(char **namesp) |
138 |
{ |
139 |
static char names[MAXHOSTNAMELEN * 3]; |
140 |
char buf[MAXHOSTNAMELEN]; |
141 |
char *pos; |
142 |
size_t bufsize; |
143 |
|
144 |
if (gethostname(buf, sizeof(buf)) < 0) { |
145 |
pjdlog_errno(LOG_ERR, "gethostname() failed"); |
146 |
return (-1); |
147 |
} |
148 |
|
149 |
/* First component of the host name. */ |
150 |
pos = strchr(buf, '.'); |
151 |
if (pos != NULL && pos != buf) { |
152 |
(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), |
153 |
sizeof(names))); |
154 |
(void)strlcat(names, ", ", sizeof(names)); |
155 |
} |
156 |
|
157 |
/* Full host name. */ |
158 |
(void)strlcat(names, buf, sizeof(names)); |
159 |
(void)strlcat(names, ", ", sizeof(names)); |
160 |
|
161 |
/* Host UUID. */ |
162 |
bufsize = sizeof(buf); |
163 |
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { |
164 |
pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); |
165 |
return (-1); |
166 |
} |
167 |
(void)strlcat(names, buf, sizeof(names)); |
168 |
|
169 |
*namesp = names; |
170 |
|
171 |
return (0); |
172 |
} |
173 |
|
174 |
void |
175 |
yyerror(const char *str) |
176 |
{ |
177 |
|
178 |
pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", |
179 |
lineno, yytext, str); |
180 |
} |
181 |
|
182 |
struct hastd_config * |
183 |
yy_config_parse(const char *config, bool exitonerror) |
184 |
{ |
185 |
int ret; |
186 |
|
187 |
curres = NULL; |
188 |
mynode = false; |
189 |
depth = 0; |
190 |
lineno = 0; |
191 |
|
192 |
depth0_timeout = HAST_TIMEOUT; |
193 |
depth0_replication = HAST_REPLICATION_FULLSYNC; |
194 |
depth0_checksum = HAST_CHECKSUM_NONE; |
195 |
depth0_compression = HAST_COMPRESSION_HOLE; |
196 |
strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); |
197 |
strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile)); |
198 |
TAILQ_INIT(&depth0_listen); |
199 |
strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, |
200 |
sizeof(depth0_listen_tcp4)); |
201 |
strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, |
202 |
sizeof(depth0_listen_tcp6)); |
203 |
depth0_exec[0] = '\0'; |
204 |
depth0_metaflush = 1; |
205 |
|
206 |
lconfig = calloc(1, sizeof(*lconfig)); |
207 |
if (lconfig == NULL) { |
208 |
pjdlog_error("Unable to allocate memory for configuration."); |
209 |
if (exitonerror) |
210 |
exit(EX_TEMPFAIL); |
211 |
return (NULL); |
212 |
} |
213 |
|
214 |
TAILQ_INIT(&lconfig->hc_listen); |
215 |
TAILQ_INIT(&lconfig->hc_resources); |
216 |
|
217 |
yyin = fopen(config, "r"); |
218 |
if (yyin == NULL) { |
219 |
pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", |
220 |
config); |
221 |
yy_config_free(lconfig); |
222 |
if (exitonerror) |
223 |
exit(EX_OSFILE); |
224 |
return (NULL); |
225 |
} |
226 |
yyrestart(yyin); |
227 |
ret = yyparse(); |
228 |
fclose(yyin); |
229 |
if (ret != 0) { |
230 |
yy_config_free(lconfig); |
231 |
if (exitonerror) |
232 |
exit(EX_CONFIG); |
233 |
return (NULL); |
234 |
} |
235 |
|
236 |
/* |
237 |
* Let's see if everything is set up. |
238 |
*/ |
239 |
if (lconfig->hc_controladdr[0] == '\0') { |
240 |
strlcpy(lconfig->hc_controladdr, depth0_control, |
241 |
sizeof(lconfig->hc_controladdr)); |
242 |
} |
243 |
if (lconfig->hc_pidfile[0] == '\0') { |
244 |
strlcpy(lconfig->hc_pidfile, depth0_pidfile, |
245 |
sizeof(lconfig->hc_pidfile)); |
246 |
} |
247 |
if (!TAILQ_EMPTY(&depth0_listen)) |
248 |
TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); |
249 |
if (TAILQ_EMPTY(&lconfig->hc_listen)) { |
250 |
struct hastd_listen *lst; |
251 |
|
252 |
if (family_supported(AF_INET)) { |
253 |
lst = calloc(1, sizeof(*lst)); |
254 |
if (lst == NULL) { |
255 |
pjdlog_error("Unable to allocate memory for listen address."); |
256 |
yy_config_free(lconfig); |
257 |
if (exitonerror) |
258 |
exit(EX_TEMPFAIL); |
259 |
return (NULL); |
260 |
} |
261 |
(void)strlcpy(lst->hl_addr, depth0_listen_tcp4, |
262 |
sizeof(lst->hl_addr)); |
263 |
TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); |
264 |
} else { |
265 |
pjdlog_debug(1, |
266 |
"No IPv4 support in the kernel, not listening on IPv4 address."); |
267 |
} |
268 |
if (family_supported(AF_INET6)) { |
269 |
lst = calloc(1, sizeof(*lst)); |
270 |
if (lst == NULL) { |
271 |
pjdlog_error("Unable to allocate memory for listen address."); |
272 |
yy_config_free(lconfig); |
273 |
if (exitonerror) |
274 |
exit(EX_TEMPFAIL); |
275 |
return (NULL); |
276 |
} |
277 |
(void)strlcpy(lst->hl_addr, depth0_listen_tcp6, |
278 |
sizeof(lst->hl_addr)); |
279 |
TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); |
280 |
} else { |
281 |
pjdlog_debug(1, |
282 |
"No IPv6 support in the kernel, not listening on IPv6 address."); |
283 |
} |
284 |
if (TAILQ_EMPTY(&lconfig->hc_listen)) { |
285 |
pjdlog_error("No address to listen on."); |
286 |
yy_config_free(lconfig); |
287 |
if (exitonerror) |
288 |
exit(EX_TEMPFAIL); |
289 |
return (NULL); |
290 |
} |
291 |
} |
292 |
TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { |
293 |
PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); |
294 |
PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); |
295 |
PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); |
296 |
|
297 |
if (curres->hr_replication == -1) { |
298 |
/* |
299 |
* Replication is not set at resource-level. |
300 |
* Use global or default setting. |
301 |
*/ |
302 |
curres->hr_replication = depth0_replication; |
303 |
} |
304 |
if (curres->hr_replication == HAST_REPLICATION_MEMSYNC) { |
305 |
pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".", |
306 |
"memsync", "fullsync"); |
307 |
curres->hr_replication = HAST_REPLICATION_FULLSYNC; |
308 |
} |
309 |
if (curres->hr_checksum == -1) { |
310 |
/* |
311 |
* Checksum is not set at resource-level. |
312 |
* Use global or default setting. |
313 |
*/ |
314 |
curres->hr_checksum = depth0_checksum; |
315 |
} |
316 |
if (curres->hr_compression == -1) { |
317 |
/* |
318 |
* Compression is not set at resource-level. |
319 |
* Use global or default setting. |
320 |
*/ |
321 |
curres->hr_compression = depth0_compression; |
322 |
} |
323 |
if (curres->hr_timeout == -1) { |
324 |
/* |
325 |
* Timeout is not set at resource-level. |
326 |
* Use global or default setting. |
327 |
*/ |
328 |
curres->hr_timeout = depth0_timeout; |
329 |
} |
330 |
if (curres->hr_exec[0] == '\0') { |
331 |
/* |
332 |
* Exec is not set at resource-level. |
333 |
* Use global or default setting. |
334 |
*/ |
335 |
strlcpy(curres->hr_exec, depth0_exec, |
336 |
sizeof(curres->hr_exec)); |
337 |
} |
338 |
if (curres->hr_metaflush == -1) { |
339 |
/* |
340 |
* Metaflush is not set at resource-level. |
341 |
* Use global or default setting. |
342 |
*/ |
343 |
curres->hr_metaflush = depth0_metaflush; |
344 |
} |
345 |
} |
346 |
|
347 |
return (lconfig); |
348 |
} |
349 |
|
350 |
void |
351 |
yy_config_free(struct hastd_config *config) |
352 |
{ |
353 |
struct hastd_listen *lst; |
354 |
struct hast_resource *res; |
355 |
|
356 |
while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { |
357 |
TAILQ_REMOVE(&depth0_listen, lst, hl_next); |
358 |
free(lst); |
359 |
} |
360 |
while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { |
361 |
TAILQ_REMOVE(&config->hc_listen, lst, hl_next); |
362 |
free(lst); |
363 |
} |
364 |
while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { |
365 |
TAILQ_REMOVE(&config->hc_resources, res, hr_next); |
366 |
free(res); |
367 |
} |
368 |
free(config); |
369 |
} |
370 |
%} |
83 |
%} |
371 |
|
84 |
|
372 |
%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH |
85 |
%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH |
Lines 1004-1006
Link Here
|
1004 |
free($2); |
717 |
free($2); |
1005 |
} |
718 |
} |
1006 |
; |
719 |
; |
|
|
720 |
|
721 |
%% |
722 |
|
723 |
static int |
724 |
isitme(const char *name) |
725 |
{ |
726 |
char buf[MAXHOSTNAMELEN]; |
727 |
char *pos; |
728 |
size_t bufsize; |
729 |
|
730 |
/* |
731 |
* First check if the given name matches our full hostname. |
732 |
*/ |
733 |
if (gethostname(buf, sizeof(buf)) < 0) { |
734 |
pjdlog_errno(LOG_ERR, "gethostname() failed"); |
735 |
return (-1); |
736 |
} |
737 |
if (strcmp(buf, name) == 0) |
738 |
return (1); |
739 |
|
740 |
/* |
741 |
* Now check if it matches first part of the host name. |
742 |
*/ |
743 |
pos = strchr(buf, '.'); |
744 |
if (pos != NULL && (size_t)(pos - buf) == strlen(name) && |
745 |
strncmp(buf, name, pos - buf) == 0) { |
746 |
return (1); |
747 |
} |
748 |
|
749 |
/* |
750 |
* At the end check if name is equal to our host's UUID. |
751 |
*/ |
752 |
bufsize = sizeof(buf); |
753 |
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { |
754 |
pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); |
755 |
return (-1); |
756 |
} |
757 |
if (strcasecmp(buf, name) == 0) |
758 |
return (1); |
759 |
|
760 |
/* |
761 |
* Looks like this isn't about us. |
762 |
*/ |
763 |
return (0); |
764 |
} |
765 |
|
766 |
static bool |
767 |
family_supported(int family) |
768 |
{ |
769 |
int sock; |
770 |
|
771 |
sock = socket(family, SOCK_STREAM, 0); |
772 |
if (sock == -1 && errno == EPROTONOSUPPORT) |
773 |
return (false); |
774 |
if (sock >= 0) |
775 |
(void)close(sock); |
776 |
return (true); |
777 |
} |
778 |
|
779 |
static int |
780 |
node_names(char **namesp) |
781 |
{ |
782 |
static char names[MAXHOSTNAMELEN * 3]; |
783 |
char buf[MAXHOSTNAMELEN]; |
784 |
char *pos; |
785 |
size_t bufsize; |
786 |
|
787 |
if (gethostname(buf, sizeof(buf)) < 0) { |
788 |
pjdlog_errno(LOG_ERR, "gethostname() failed"); |
789 |
return (-1); |
790 |
} |
791 |
|
792 |
/* First component of the host name. */ |
793 |
pos = strchr(buf, '.'); |
794 |
if (pos != NULL && pos != buf) { |
795 |
(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), |
796 |
sizeof(names))); |
797 |
(void)strlcat(names, ", ", sizeof(names)); |
798 |
} |
799 |
|
800 |
/* Full host name. */ |
801 |
(void)strlcat(names, buf, sizeof(names)); |
802 |
(void)strlcat(names, ", ", sizeof(names)); |
803 |
|
804 |
/* Host UUID. */ |
805 |
bufsize = sizeof(buf); |
806 |
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { |
807 |
pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); |
808 |
return (-1); |
809 |
} |
810 |
(void)strlcat(names, buf, sizeof(names)); |
811 |
|
812 |
*namesp = names; |
813 |
|
814 |
return (0); |
815 |
} |
816 |
|
817 |
void |
818 |
yyerror(const char *str) |
819 |
{ |
820 |
|
821 |
pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", |
822 |
lineno, yytext, str); |
823 |
} |
824 |
|
825 |
struct hastd_config * |
826 |
yy_config_parse(const char *config, bool exitonerror) |
827 |
{ |
828 |
int ret; |
829 |
|
830 |
curres = NULL; |
831 |
mynode = false; |
832 |
depth = 0; |
833 |
lineno = 0; |
834 |
|
835 |
depth0_timeout = HAST_TIMEOUT; |
836 |
depth0_replication = HAST_REPLICATION_FULLSYNC; |
837 |
depth0_checksum = HAST_CHECKSUM_NONE; |
838 |
depth0_compression = HAST_COMPRESSION_HOLE; |
839 |
strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); |
840 |
strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile)); |
841 |
TAILQ_INIT(&depth0_listen); |
842 |
strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, |
843 |
sizeof(depth0_listen_tcp4)); |
844 |
strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, |
845 |
sizeof(depth0_listen_tcp6)); |
846 |
depth0_exec[0] = '\0'; |
847 |
depth0_metaflush = 1; |
848 |
|
849 |
lconfig = calloc(1, sizeof(*lconfig)); |
850 |
if (lconfig == NULL) { |
851 |
pjdlog_error("Unable to allocate memory for configuration."); |
852 |
if (exitonerror) |
853 |
exit(EX_TEMPFAIL); |
854 |
return (NULL); |
855 |
} |
856 |
|
857 |
TAILQ_INIT(&lconfig->hc_listen); |
858 |
TAILQ_INIT(&lconfig->hc_resources); |
859 |
|
860 |
yyin = fopen(config, "r"); |
861 |
if (yyin == NULL) { |
862 |
pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", |
863 |
config); |
864 |
yy_config_free(lconfig); |
865 |
if (exitonerror) |
866 |
exit(EX_OSFILE); |
867 |
return (NULL); |
868 |
} |
869 |
yyrestart(yyin); |
870 |
ret = yyparse(); |
871 |
fclose(yyin); |
872 |
if (ret != 0) { |
873 |
yy_config_free(lconfig); |
874 |
if (exitonerror) |
875 |
exit(EX_CONFIG); |
876 |
return (NULL); |
877 |
} |
878 |
|
879 |
/* |
880 |
* Let's see if everything is set up. |
881 |
*/ |
882 |
if (lconfig->hc_controladdr[0] == '\0') { |
883 |
strlcpy(lconfig->hc_controladdr, depth0_control, |
884 |
sizeof(lconfig->hc_controladdr)); |
885 |
} |
886 |
if (lconfig->hc_pidfile[0] == '\0') { |
887 |
strlcpy(lconfig->hc_pidfile, depth0_pidfile, |
888 |
sizeof(lconfig->hc_pidfile)); |
889 |
} |
890 |
if (!TAILQ_EMPTY(&depth0_listen)) |
891 |
TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); |
892 |
if (TAILQ_EMPTY(&lconfig->hc_listen)) { |
893 |
struct hastd_listen *lst; |
894 |
|
895 |
if (family_supported(AF_INET)) { |
896 |
lst = calloc(1, sizeof(*lst)); |
897 |
if (lst == NULL) { |
898 |
pjdlog_error("Unable to allocate memory for listen address."); |
899 |
yy_config_free(lconfig); |
900 |
if (exitonerror) |
901 |
exit(EX_TEMPFAIL); |
902 |
return (NULL); |
903 |
} |
904 |
(void)strlcpy(lst->hl_addr, depth0_listen_tcp4, |
905 |
sizeof(lst->hl_addr)); |
906 |
TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); |
907 |
} else { |
908 |
pjdlog_debug(1, |
909 |
"No IPv4 support in the kernel, not listening on IPv4 address."); |
910 |
} |
911 |
if (family_supported(AF_INET6)) { |
912 |
lst = calloc(1, sizeof(*lst)); |
913 |
if (lst == NULL) { |
914 |
pjdlog_error("Unable to allocate memory for listen address."); |
915 |
yy_config_free(lconfig); |
916 |
if (exitonerror) |
917 |
exit(EX_TEMPFAIL); |
918 |
return (NULL); |
919 |
} |
920 |
(void)strlcpy(lst->hl_addr, depth0_listen_tcp6, |
921 |
sizeof(lst->hl_addr)); |
922 |
TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); |
923 |
} else { |
924 |
pjdlog_debug(1, |
925 |
"No IPv6 support in the kernel, not listening on IPv6 address."); |
926 |
} |
927 |
if (TAILQ_EMPTY(&lconfig->hc_listen)) { |
928 |
pjdlog_error("No address to listen on."); |
929 |
yy_config_free(lconfig); |
930 |
if (exitonerror) |
931 |
exit(EX_TEMPFAIL); |
932 |
return (NULL); |
933 |
} |
934 |
} |
935 |
TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { |
936 |
PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); |
937 |
PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); |
938 |
PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); |
939 |
|
940 |
if (curres->hr_replication == -1) { |
941 |
/* |
942 |
* Replication is not set at resource-level. |
943 |
* Use global or default setting. |
944 |
*/ |
945 |
curres->hr_replication = depth0_replication; |
946 |
} |
947 |
if (curres->hr_replication == HAST_REPLICATION_MEMSYNC) { |
948 |
pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".", |
949 |
"memsync", "fullsync"); |
950 |
curres->hr_replication = HAST_REPLICATION_FULLSYNC; |
951 |
} |
952 |
if (curres->hr_checksum == -1) { |
953 |
/* |
954 |
* Checksum is not set at resource-level. |
955 |
* Use global or default setting. |
956 |
*/ |
957 |
curres->hr_checksum = depth0_checksum; |
958 |
} |
959 |
if (curres->hr_compression == -1) { |
960 |
/* |
961 |
* Compression is not set at resource-level. |
962 |
* Use global or default setting. |
963 |
*/ |
964 |
curres->hr_compression = depth0_compression; |
965 |
} |
966 |
if (curres->hr_timeout == -1) { |
967 |
/* |
968 |
* Timeout is not set at resource-level. |
969 |
* Use global or default setting. |
970 |
*/ |
971 |
curres->hr_timeout = depth0_timeout; |
972 |
} |
973 |
if (curres->hr_exec[0] == '\0') { |
974 |
/* |
975 |
* Exec is not set at resource-level. |
976 |
* Use global or default setting. |
977 |
*/ |
978 |
strlcpy(curres->hr_exec, depth0_exec, |
979 |
sizeof(curres->hr_exec)); |
980 |
} |
981 |
if (curres->hr_metaflush == -1) { |
982 |
/* |
983 |
* Metaflush is not set at resource-level. |
984 |
* Use global or default setting. |
985 |
*/ |
986 |
curres->hr_metaflush = depth0_metaflush; |
987 |
} |
988 |
} |
989 |
|
990 |
return (lconfig); |
991 |
} |
992 |
|
993 |
void |
994 |
yy_config_free(struct hastd_config *config) |
995 |
{ |
996 |
struct hastd_listen *lst; |
997 |
struct hast_resource *res; |
998 |
|
999 |
while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { |
1000 |
TAILQ_REMOVE(&depth0_listen, lst, hl_next); |
1001 |
free(lst); |
1002 |
} |
1003 |
while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { |
1004 |
TAILQ_REMOVE(&config->hc_listen, lst, hl_next); |
1005 |
free(lst); |
1006 |
} |
1007 |
while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { |
1008 |
TAILQ_REMOVE(&config->hc_resources, res, hr_next); |
1009 |
free(res); |
1010 |
} |
1011 |
free(config); |
1012 |
} |