corosync  2.3.2
coroparse.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006-2013 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Patrick Caulfield (pcaulfie@redhat.com)
7  * Jan Friesse (jfriesse@redhat.com)
8  *
9  * This software licensed under BSD license, the text of which follows:
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  *
14  * - Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  * - Redistributions in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  * - Neither the name of the MontaVista Software, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived from this
21  * software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 
38 #include <sys/types.h>
39 #include <sys/uio.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/un.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <errno.h>
50 #include <string.h>
51 #include <dirent.h>
52 #include <limits.h>
53 #include <stddef.h>
54 #include <grp.h>
55 #include <pwd.h>
56 
57 #include <corosync/list.h>
58 #include <qb/qbutil.h>
59 #define LOGSYS_UTILS_ONLY 1
60 #include <corosync/logsys.h>
61 #include <corosync/icmap.h>
62 
63 #include "main.h"
64 #include "util.h"
65 
72 };
73 
74 typedef int (*parser_cb_f)(const char *path,
75  char *key,
76  char *value,
77  enum parser_cb_type type,
78  const char **error_string,
79  icmap_map_t config_map,
80  void *user_data);
81 
96 };
97 
99  char *key;
100  char *value;
101  struct list_head list;
102 };
103 
106 
108  char *bindnetaddr;
109  char *mcastaddr;
110  char *broadcast;
112  int ttl;
113 
115  char *subsys;
118 
121 };
122 
123 static int read_config_file_into_icmap(
124  const char **error_string, icmap_map_t config_map);
125 static char error_string_response[512];
126 
127 static int uid_determine (const char *req_user)
128 {
129  int pw_uid = 0;
130  struct passwd passwd;
131  struct passwd* pwdptr = &passwd;
132  struct passwd* temp_pwd_pt;
133  char *pwdbuffer;
134  int pwdlinelen, rc;
135  long int id;
136  char *ep;
137 
138  id = strtol(req_user, &ep, 10);
139  if (*ep == '\0' && id >= 0 && id <= UINT_MAX) {
140  return (id);
141  }
142 
143  pwdlinelen = sysconf (_SC_GETPW_R_SIZE_MAX);
144 
145  if (pwdlinelen == -1) {
146  pwdlinelen = 256;
147  }
148 
149  pwdbuffer = malloc (pwdlinelen);
150 
151  while ((rc = getpwnam_r (req_user, pwdptr, pwdbuffer, pwdlinelen, &temp_pwd_pt)) == ERANGE) {
152  char *n;
153 
154  pwdlinelen *= 2;
155  if (pwdlinelen <= 32678) {
156  n = realloc (pwdbuffer, pwdlinelen);
157  if (n != NULL) {
158  pwdbuffer = n;
159  continue;
160  }
161  }
162  }
163  if (rc != 0) {
164  free (pwdbuffer);
165  sprintf (error_string_response, "getpwnam_r(): %s", strerror(rc));
166  return (-1);
167  }
168  if (temp_pwd_pt == NULL) {
169  free (pwdbuffer);
170  sprintf (error_string_response,
171  "The '%s' user is not found in /etc/passwd, please read the documentation.",
172  req_user);
173  return (-1);
174  }
175  pw_uid = passwd.pw_uid;
176  free (pwdbuffer);
177 
178  return pw_uid;
179 }
180 
181 static int gid_determine (const char *req_group)
182 {
183  int corosync_gid = 0;
184  struct group group;
185  struct group * grpptr = &group;
186  struct group * temp_grp_pt;
187  char *grpbuffer;
188  int grplinelen, rc;
189  long int id;
190  char *ep;
191 
192  id = strtol(req_group, &ep, 10);
193  if (*ep == '\0' && id >= 0 && id <= UINT_MAX) {
194  return (id);
195  }
196 
197  grplinelen = sysconf (_SC_GETGR_R_SIZE_MAX);
198 
199  if (grplinelen == -1) {
200  grplinelen = 256;
201  }
202 
203  grpbuffer = malloc (grplinelen);
204 
205  while ((rc = getgrnam_r (req_group, grpptr, grpbuffer, grplinelen, &temp_grp_pt)) == ERANGE) {
206  char *n;
207 
208  grplinelen *= 2;
209  if (grplinelen <= 32678) {
210  n = realloc (grpbuffer, grplinelen);
211  if (n != NULL) {
212  grpbuffer = n;
213  continue;
214  }
215  }
216  }
217  if (rc != 0) {
218  free (grpbuffer);
219  sprintf (error_string_response, "getgrnam_r(): %s", strerror(rc));
220  return (-1);
221  }
222  if (temp_grp_pt == NULL) {
223  free (grpbuffer);
224  sprintf (error_string_response,
225  "The '%s' group is not found in /etc/group, please read the documentation.",
226  req_group);
227  return (-1);
228  }
229  corosync_gid = group.gr_gid;
230  free (grpbuffer);
231 
232  return corosync_gid;
233 }
234 static char *strchr_rs (const char *haystack, int byte)
235 {
236  const char *end_address = strchr (haystack, byte);
237  if (end_address) {
238  end_address += 1; /* skip past { or = */
239 
240  while (*end_address == ' ' || *end_address == '\t')
241  end_address++;
242  }
243 
244  return ((char *) end_address);
245 }
246 
247 int coroparse_configparse (icmap_map_t config_map, const char **error_string)
248 {
249  if (read_config_file_into_icmap(error_string, config_map)) {
250  return -1;
251  }
252 
253  return 0;
254 }
255 
256 static char *remove_whitespace(char *string, int remove_colon_and_brace)
257 {
258  char *start;
259  char *end;
260 
261  start = string;
262  while (*start == ' ' || *start == '\t')
263  start++;
264 
265  end = start+(strlen(start))-1;
266  while ((*end == ' ' || *end == '\t' || (remove_colon_and_brace && (*end == ':' || *end == '{'))) && end > start)
267  end--;
268  if (end != start)
269  *(end+1) = '\0';
270 
271  return start;
272 }
273 
274 
275 
276 static int parse_section(FILE *fp,
277  char *path,
278  const char **error_string,
279  int depth,
280  parser_cb_f parser_cb,
281  icmap_map_t config_map,
282  void *user_data)
283 {
284  char line[512];
285  int i;
286  char *loc;
287  int ignore_line;
288  char new_keyname[ICMAP_KEYNAME_MAXLEN];
289 
290  if (strcmp(path, "") == 0) {
291  parser_cb("", NULL, NULL, PARSER_CB_START, error_string, config_map, user_data);
292  }
293 
294  while (fgets (line, sizeof (line), fp)) {
295  if (strlen(line) > 0) {
296  if (line[strlen(line) - 1] == '\n')
297  line[strlen(line) - 1] = '\0';
298  if (strlen (line) > 0 && line[strlen(line) - 1] == '\r')
299  line[strlen(line) - 1] = '\0';
300  }
301  /*
302  * Clear out white space and tabs
303  */
304  for (i = strlen (line) - 1; i > -1; i--) {
305  if (line[i] == '\t' || line[i] == ' ') {
306  line[i] = '\0';
307  } else {
308  break;
309  }
310  }
311 
312  ignore_line = 1;
313  for (i = 0; i < strlen (line); i++) {
314  if (line[i] != '\t' && line[i] != ' ') {
315  if (line[i] != '#')
316  ignore_line = 0;
317 
318  break;
319  }
320  }
321  /*
322  * Clear out comments and empty lines
323  */
324  if (ignore_line) {
325  continue;
326  }
327 
328  /* New section ? */
329  if ((loc = strchr_rs (line, '{'))) {
330  char *section = remove_whitespace(line, 1);
331 
332  loc--;
333  *loc = '\0';
334 
335  if (strlen(path) + strlen(section) + 1 >= ICMAP_KEYNAME_MAXLEN) {
336  *error_string = "parser error: Start of section makes total cmap path too long";
337  return -1;
338  }
339  strcpy(new_keyname, path);
340  if (strcmp(path, "") != 0) {
341  strcat(new_keyname, ".");
342  }
343  strcat(new_keyname, section);
344 
345  if (!parser_cb(new_keyname, NULL, NULL, PARSER_CB_SECTION_START, error_string, config_map, user_data)) {
346  return -1;
347  }
348 
349  if (parse_section(fp, new_keyname, error_string, depth + 1, parser_cb, config_map, user_data))
350  return -1;
351 
352  continue ;
353  }
354 
355  /* New key/value */
356  if ((loc = strchr_rs (line, ':'))) {
357  char *key;
358  char *value;
359 
360  *(loc-1) = '\0';
361  key = remove_whitespace(line, 1);
362  value = remove_whitespace(loc, 0);
363 
364  if (strlen(path) + strlen(key) + 1 >= ICMAP_KEYNAME_MAXLEN) {
365  *error_string = "parser error: New key makes total cmap path too long";
366  return -1;
367  }
368  strcpy(new_keyname, path);
369  if (strcmp(path, "") != 0) {
370  strcat(new_keyname, ".");
371  }
372  strcat(new_keyname, key);
373 
374  if (!parser_cb(new_keyname, key, value, PARSER_CB_ITEM, error_string, config_map, user_data)) {
375  return -1;
376  }
377 
378  continue ;
379  }
380 
381  if (strchr_rs (line, '}')) {
382  if (depth == 0) {
383  *error_string = "parser error: Unexpected closing brace";
384 
385  return -1;
386  }
387 
388  if (!parser_cb(path, NULL, NULL, PARSER_CB_SECTION_END, error_string, config_map, user_data)) {
389  return -1;
390  }
391 
392  return 0;
393  }
394  }
395 
396  if (strcmp(path, "") != 0) {
397  *error_string = "parser error: Missing closing brace";
398  return -1;
399  }
400 
401  if (strcmp(path, "") == 0) {
402  parser_cb("", NULL, NULL, PARSER_CB_END, error_string, config_map, user_data);
403  }
404 
405  return 0;
406 }
407 
408 static int safe_atoi(const char *str, int *res)
409 {
410  int val;
411  char *endptr;
412 
413  errno = 0;
414 
415  val = strtol(str, &endptr, 10);
416  if (errno == ERANGE) {
417  return (-1);
418  }
419 
420  if (endptr == str) {
421  return (-1);
422  }
423 
424  if (*endptr != '\0') {
425  return (-1);
426  }
427 
428  *res = val;
429  return (0);
430 }
431 
432 static int str_to_ull(const char *str, unsigned long long int *res)
433 {
434  unsigned long long int val;
435  char *endptr;
436 
437  errno = 0;
438 
439  val = strtoull(str, &endptr, 10);
440  if (errno == ERANGE) {
441  return (-1);
442  }
443 
444  if (endptr == str) {
445  return (-1);
446  }
447 
448  if (*endptr != '\0') {
449  return (-1);
450  }
451 
452  *res = val;
453  return (0);
454 }
455 
456 static int main_config_parser_cb(const char *path,
457  char *key,
458  char *value,
459  enum parser_cb_type type,
460  const char **error_string,
461  icmap_map_t config_map,
462  void *user_data)
463 {
464  int i;
465  unsigned long long int ull;
466  int add_as_string;
467  char key_name[ICMAP_KEYNAME_MAXLEN];
468  static char formated_err[256];
469  struct main_cp_cb_data *data = (struct main_cp_cb_data *)user_data;
470  struct key_value_list_item *kv_item;
471  struct list_head *iter, *iter_next;
472  int uid, gid;
473 
474  switch (type) {
475  case PARSER_CB_START:
476  memset(data, 0, sizeof(struct main_cp_cb_data));
478  break;
479  case PARSER_CB_END:
480  break;
481  case PARSER_CB_ITEM:
482  add_as_string = 1;
483 
484  switch (data->state) {
486  break;
488  if ((strcmp(path, "pload.count") == 0) ||
489  (strcmp(path, "pload.size") == 0)) {
490  if (safe_atoi(value, &i) != 0) {
491  goto atoi_error;
492  }
493  icmap_set_uint32_r(config_map, path, i);
494  add_as_string = 0;
495  }
496  break;
498  if ((strcmp(path, "quorum.expected_votes") == 0) ||
499  (strcmp(path, "quorum.votes") == 0) ||
500  (strcmp(path, "quorum.last_man_standing_window") == 0) ||
501  (strcmp(path, "quorum.leaving_timeout") == 0)) {
502  if (safe_atoi(value, &i) != 0) {
503  goto atoi_error;
504  }
505  icmap_set_uint32_r(config_map, path, i);
506  add_as_string = 0;
507  }
508 
509  if ((strcmp(path, "quorum.two_node") == 0) ||
510  (strcmp(path, "quorum.allow_downscale") == 0) ||
511  (strcmp(path, "quorum.wait_for_all") == 0) ||
512  (strcmp(path, "quorum.auto_tie_breaker") == 0) ||
513  (strcmp(path, "quorum.last_man_standing") == 0)) {
514  if (safe_atoi(value, &i) != 0) {
515  goto atoi_error;
516  }
517  icmap_set_uint8_r(config_map, path, i);
518  add_as_string = 0;
519  }
520  break;
522  if ((strcmp(path, "quorum.device.timeout") == 0) ||
523  (strcmp(path, "quorum.device.votes") == 0)) {
524  if (safe_atoi(value, &i) != 0) {
525  goto atoi_error;
526  }
527  icmap_set_uint32_r(config_map, path, i);
528  add_as_string = 0;
529  }
530  if ((strcmp(path, "quorum.device.master_wins") == 0)) {
531  if (safe_atoi(value, &i) != 0) {
532  goto atoi_error;
533  }
534  icmap_set_uint8_r(config_map, path, i);
535  add_as_string = 0;
536  }
537  break;
539  if ((strcmp(path, "totem.version") == 0) ||
540  (strcmp(path, "totem.nodeid") == 0) ||
541  (strcmp(path, "totem.threads") == 0) ||
542  (strcmp(path, "totem.token") == 0) ||
543  (strcmp(path, "totem.token_retransmit") == 0) ||
544  (strcmp(path, "totem.hold") == 0) ||
545  (strcmp(path, "totem.token_retransmits_before_loss_const") == 0) ||
546  (strcmp(path, "totem.join") == 0) ||
547  (strcmp(path, "totem.send_join") == 0) ||
548  (strcmp(path, "totem.consensus") == 0) ||
549  (strcmp(path, "totem.merge") == 0) ||
550  (strcmp(path, "totem.downcheck") == 0) ||
551  (strcmp(path, "totem.fail_recv_const") == 0) ||
552  (strcmp(path, "totem.seqno_unchanged_const") == 0) ||
553  (strcmp(path, "totem.rrp_token_expired_timeout") == 0) ||
554  (strcmp(path, "totem.rrp_problem_count_timeout") == 0) ||
555  (strcmp(path, "totem.rrp_problem_count_threshold") == 0) ||
556  (strcmp(path, "totem.rrp_problem_count_mcast_threshold") == 0) ||
557  (strcmp(path, "totem.rrp_autorecovery_check_timeout") == 0) ||
558  (strcmp(path, "totem.heartbeat_failures_allowed") == 0) ||
559  (strcmp(path, "totem.max_network_delay") == 0) ||
560  (strcmp(path, "totem.window_size") == 0) ||
561  (strcmp(path, "totem.max_messages") == 0) ||
562  (strcmp(path, "totem.miss_count_const") == 0) ||
563  (strcmp(path, "totem.netmtu") == 0)) {
564  if (safe_atoi(value, &i) != 0) {
565  goto atoi_error;
566  }
567  icmap_set_uint32_r(config_map,path, i);
568  add_as_string = 0;
569  }
570  if (strcmp(path, "totem.config_version") == 0) {
571  if (str_to_ull(value, &ull) != 0) {
572  goto atoi_error;
573  }
574  icmap_set_uint64_r(config_map, path, ull);
575  add_as_string = 0;
576  }
577  if (strcmp(path, "totem.ip_version") == 0) {
578  if ((strcmp(value, "ipv4") != 0) &&
579  (strcmp(value, "ipv6") != 0)) {
580  *error_string = "Invalid ip_version type";
581 
582  return (0);
583  }
584  }
585  if (strcmp(path, "totem.crypto_type") == 0) {
586  if ((strcmp(value, "nss") != 0) &&
587  (strcmp(value, "aes256") != 0) &&
588  (strcmp(value, "aes192") != 0) &&
589  (strcmp(value, "aes128") != 0) &&
590  (strcmp(value, "3des") != 0)) {
591  *error_string = "Invalid crypto type";
592 
593  return (0);
594  }
595  }
596  if (strcmp(path, "totem.crypto_cipher") == 0) {
597  if ((strcmp(value, "none") != 0) &&
598  (strcmp(value, "aes256") != 0) &&
599  (strcmp(value, "aes192") != 0) &&
600  (strcmp(value, "aes128") != 0) &&
601  (strcmp(value, "3des") != 0)) {
602  *error_string = "Invalid cipher type";
603 
604  return (0);
605  }
606  }
607  if (strcmp(path, "totem.crypto_hash") == 0) {
608  if ((strcmp(value, "none") != 0) &&
609  (strcmp(value, "md5") != 0) &&
610  (strcmp(value, "sha1") != 0) &&
611  (strcmp(value, "sha256") != 0) &&
612  (strcmp(value, "sha384") != 0) &&
613  (strcmp(value, "sha512") != 0)) {
614  *error_string = "Invalid hash type";
615 
616  return (0);
617  }
618  }
619  break;
620 
622  if (strcmp(path, "qb.ipc_type") == 0) {
623  if ((strcmp(value, "native") != 0) &&
624  (strcmp(value, "shm") != 0) &&
625  (strcmp(value, "socket") != 0)) {
626  *error_string = "Invalid qb ipc_type";
627 
628  return (0);
629  }
630  }
631  break;
632 
634  if (strcmp(path, "totem.interface.ringnumber") == 0) {
635  if (safe_atoi(value, &i) != 0) {
636  goto atoi_error;
637  }
638 
639  data->ringnumber = i;
640  add_as_string = 0;
641  }
642  if (strcmp(path, "totem.interface.bindnetaddr") == 0) {
643  data->bindnetaddr = strdup(value);
644  add_as_string = 0;
645  }
646  if (strcmp(path, "totem.interface.mcastaddr") == 0) {
647  data->mcastaddr = strdup(value);
648  add_as_string = 0;
649  }
650  if (strcmp(path, "totem.interface.broadcast") == 0) {
651  data->broadcast = strdup(value);
652  add_as_string = 0;
653  }
654  if (strcmp(path, "totem.interface.mcastport") == 0) {
655  if (safe_atoi(value, &i) != 0) {
656  goto atoi_error;
657  }
658  data->mcastport = i;
659  if (data->mcastport < 0 || data->mcastport > 65535) {
660  *error_string = "Invalid multicast port (should be 0..65535)";
661 
662  return (0);
663  };
664  add_as_string = 0;
665  }
666  if (strcmp(path, "totem.interface.ttl") == 0) {
667  if (safe_atoi(value, &i) != 0) {
668  goto atoi_error;
669  }
670  data->ttl = i;
671  if (data->ttl < 0 || data->ttl > 255) {
672  *error_string = "Invalid TTL (should be 0..255)";
673 
674  return (0);
675  };
676  add_as_string = 0;
677  }
678  break;
680  if (strcmp(key, "subsys") == 0) {
681  data->subsys = strdup(value);
682  if (data->subsys == NULL) {
683  *error_string = "Can't alloc memory";
684 
685  return (0);
686  }
687  } else {
688  kv_item = malloc(sizeof(*kv_item));
689  if (kv_item == NULL) {
690  *error_string = "Can't alloc memory";
691 
692  return (0);
693  }
694  memset(kv_item, 0, sizeof(*kv_item));
695 
696  kv_item->key = strdup(key);
697  kv_item->value = strdup(value);
698  if (kv_item->key == NULL || kv_item->value == NULL) {
699  free(kv_item);
700  *error_string = "Can't alloc memory";
701 
702  return (0);
703  }
704  list_init(&kv_item->list);
705  list_add(&kv_item->list, &data->logger_subsys_items_head);
706  }
707  add_as_string = 0;
708  break;
710  if (strcmp(key, "subsys") == 0) {
711  data->subsys = strdup(value);
712  if (data->subsys == NULL) {
713  *error_string = "Can't alloc memory";
714 
715  return (0);
716  }
717  } else if (strcmp(key, "name") == 0) {
718  data->logging_daemon_name = strdup(value);
719  if (data->logging_daemon_name == NULL) {
720  *error_string = "Can't alloc memory";
721 
722  return (0);
723  }
724  } else {
725  kv_item = malloc(sizeof(*kv_item));
726  if (kv_item == NULL) {
727  *error_string = "Can't alloc memory";
728 
729  return (0);
730  }
731  memset(kv_item, 0, sizeof(*kv_item));
732 
733  kv_item->key = strdup(key);
734  kv_item->value = strdup(value);
735  if (kv_item->key == NULL || kv_item->value == NULL) {
736  free(kv_item);
737  *error_string = "Can't alloc memory";
738 
739  return (0);
740  }
741  list_init(&kv_item->list);
742  list_add(&kv_item->list, &data->logger_subsys_items_head);
743  }
744  add_as_string = 0;
745  break;
747  if (strcmp(key, "uid") == 0) {
748  uid = uid_determine(value);
749  if (uid == -1) {
750  *error_string = error_string_response;
751  return (0);
752  }
753  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.uid.%u",
754  uid);
755  icmap_set_uint8_r(config_map, key_name, 1);
756  add_as_string = 0;
757  } else if (strcmp(key, "gid") == 0) {
758  gid = gid_determine(value);
759  if (gid == -1) {
760  *error_string = error_string_response;
761  return (0);
762  }
763  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.gid.%u",
764  gid);
765  icmap_set_uint8_r(config_map, key_name, 1);
766  add_as_string = 0;
767  } else {
768  *error_string = "uidgid: Only uid and gid are allowed items";
769  return (0);
770  }
771  break;
773  if (strcmp(key, "memberaddr") != 0) {
774  *error_string = "Only memberaddr is allowed in member section";
775 
776  return (0);
777  }
778 
779  kv_item = malloc(sizeof(*kv_item));
780  if (kv_item == NULL) {
781  *error_string = "Can't alloc memory";
782 
783  return (0);
784  }
785  memset(kv_item, 0, sizeof(*kv_item));
786 
787  kv_item->key = strdup(key);
788  kv_item->value = strdup(value);
789  if (kv_item->key == NULL || kv_item->value == NULL) {
790  free(kv_item);
791  *error_string = "Can't alloc memory";
792 
793  return (0);
794  }
795  list_init(&kv_item->list);
796  list_add(&kv_item->list, &data->member_items_head);
797  add_as_string = 0;
798  break;
800  break;
802  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.%s", data->node_number, key);
803  if ((strcmp(key, "nodeid") == 0) ||
804  (strcmp(key, "quorum_votes") == 0)) {
805  if (safe_atoi(value, &i) != 0) {
806  goto atoi_error;
807  }
808 
809  icmap_set_uint32_r(config_map, key_name, i);
810  add_as_string = 0;
811  }
812 
813  if (strcmp(key, "ring0_addr") == 0) {
814  data->ring0_addr_added = 1;
815  }
816 
817  if (add_as_string) {
818  icmap_set_string_r(config_map, key_name, value);
819  add_as_string = 0;
820  }
821  break;
822  }
823 
824  if (add_as_string) {
825  icmap_set_string_r(config_map, path, value);
826  }
827  break;
829  if (strcmp(path, "totem.interface") == 0) {
831  data->ringnumber = 0;
832  data->mcastport = -1;
833  data->ttl = -1;
834  list_init(&data->member_items_head);
835  };
836  if (strcmp(path, "totem") == 0) {
838  };
839  if (strcmp(path, "qb") == 0) {
841  }
842  if (strcmp(path, "logging.logger_subsys") == 0) {
844  list_init(&data->logger_subsys_items_head);
845  data->subsys = NULL;
846  }
847  if (strcmp(path, "logging.logging_daemon") == 0) {
849  list_init(&data->logger_subsys_items_head);
850  data->subsys = NULL;
851  data->logging_daemon_name = NULL;
852  }
853  if (strcmp(path, "uidgid") == 0) {
855  }
856  if (strcmp(path, "totem.interface.member") == 0) {
858  }
859  if (strcmp(path, "quorum") == 0) {
861  }
862  if (strcmp(path, "quorum.device") == 0) {
864  }
865  if (strcmp(path, "nodelist") == 0) {
867  data->node_number = 0;
868  }
869  if (strcmp(path, "nodelist.node") == 0) {
871  data->ring0_addr_added = 0;
872  }
873  break;
875  switch (data->state) {
877  break;
880  break;
882  /*
883  * Create new interface section
884  */
885  if (data->bindnetaddr != NULL) {
886  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr",
887  data->ringnumber);
888  icmap_set_string_r(config_map, key_name, data->bindnetaddr);
889 
890  free(data->bindnetaddr);
891  data->bindnetaddr = NULL;
892  }
893 
894  if (data->mcastaddr != NULL) {
895  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr",
896  data->ringnumber);
897  icmap_set_string_r(config_map, key_name, data->mcastaddr);
898 
899  free(data->mcastaddr);
900  data->mcastaddr = NULL;
901  }
902 
903  if (data->broadcast != NULL) {
904  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast",
905  data->ringnumber);
906  icmap_set_string_r(config_map, key_name, data->broadcast);
907 
908  free(data->broadcast);
909  data->broadcast = NULL;
910  }
911 
912  if (data->mcastport > -1) {
913  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport",
914  data->ringnumber);
915  icmap_set_uint16_r(config_map, key_name, data->mcastport);
916  }
917 
918  if (data->ttl > -1) {
919  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl",
920  data->ringnumber);
921  icmap_set_uint8_r(config_map, key_name, data->ttl);
922  }
923 
924  i = 0;
925  for (iter = data->member_items_head.next;
926  iter != &data->member_items_head; iter = iter_next) {
927  kv_item = list_entry(iter, struct key_value_list_item, list);
928 
929  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.%u",
930  data->ringnumber, i);
931  icmap_set_string_r(config_map, key_name, kv_item->value);
932 
933  iter_next = iter->next;
934 
935  free(kv_item->value);
936  free(kv_item->key);
937  free(kv_item);
938  i++;
939  }
940 
942  break;
945  break;
948  break;
950  if (data->subsys == NULL) {
951  *error_string = "No subsys key in logger_subsys directive";
952 
953  return (0);
954  }
955 
956  for (iter = data->logger_subsys_items_head.next;
957  iter != &data->logger_subsys_items_head; iter = iter_next) {
958  kv_item = list_entry(iter, struct key_value_list_item, list);
959 
960  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.%s",
961  data->subsys, kv_item->key);
962  icmap_set_string_r(config_map, key_name, kv_item->value);
963 
964  iter_next = iter->next;
965 
966  free(kv_item->value);
967  free(kv_item->key);
968  free(kv_item);
969  }
970 
971  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.subsys",
972  data->subsys);
973  icmap_set_string_r(config_map, key_name, data->subsys);
974 
975  free(data->subsys);
976 
978  break;
980  if (data->logging_daemon_name == NULL) {
981  *error_string = "No name key in logging_daemon directive";
982 
983  return (0);
984  }
985 
986  for (iter = data->logger_subsys_items_head.next;
987  iter != &data->logger_subsys_items_head; iter = iter_next) {
988  kv_item = list_entry(iter, struct key_value_list_item, list);
989 
990  if (data->subsys == NULL) {
991  if (strcmp(data->logging_daemon_name, "corosync") == 0) {
992  snprintf(key_name, ICMAP_KEYNAME_MAXLEN,
993  "logging.%s",
994  kv_item->key);
995  } else {
996  snprintf(key_name, ICMAP_KEYNAME_MAXLEN,
997  "logging.logging_daemon.%s.%s",
998  data->logging_daemon_name, kv_item->key);
999  }
1000  } else {
1001  if (strcmp(data->logging_daemon_name, "corosync") == 0) {
1002  snprintf(key_name, ICMAP_KEYNAME_MAXLEN,
1003  "logging.logger_subsys.%s.%s",
1004  data->subsys,
1005  kv_item->key);
1006  } else {
1007  snprintf(key_name, ICMAP_KEYNAME_MAXLEN,
1008  "logging.logging_daemon.%s.%s.%s",
1009  data->logging_daemon_name, data->subsys,
1010  kv_item->key);
1011  }
1012  }
1013  icmap_set_string_r(config_map, key_name, kv_item->value);
1014 
1015  iter_next = iter->next;
1016 
1017  free(kv_item->value);
1018  free(kv_item->key);
1019  free(kv_item);
1020  }
1021 
1022  if (data->subsys == NULL) {
1023  if (strcmp(data->logging_daemon_name, "corosync") != 0) {
1024  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.name",
1025  data->logging_daemon_name);
1026  icmap_set_string_r(config_map, key_name, data->logging_daemon_name);
1027  }
1028  } else {
1029  if (strcmp(data->logging_daemon_name, "corosync") == 0) {
1030  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logger_subsys.%s.subsys",
1031  data->subsys);
1032  icmap_set_string_r(config_map, key_name, data->subsys);
1033 
1034  } else {
1035  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.%s.subsys",
1036  data->logging_daemon_name, data->subsys);
1037  icmap_set_string_r(config_map, key_name, data->subsys);
1038  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "logging.logging_daemon.%s.%s.name",
1039  data->logging_daemon_name, data->subsys);
1040  icmap_set_string_r(config_map, key_name, data->logging_daemon_name);
1041  }
1042  }
1043 
1044  free(data->subsys);
1045  free(data->logging_daemon_name);
1046 
1048  break;
1051  break;
1054  break;
1057  break;
1060  break;
1063  break;
1065  if (!data->ring0_addr_added) {
1066  *error_string = "No ring0_addr specified for node";
1067 
1068  return (0);
1069  }
1070  data->node_number++;
1072  break;
1073  }
1074  break;
1075  }
1076 
1077  return (1);
1078 
1079 atoi_error:
1080  snprintf(formated_err, sizeof(formated_err),
1081  "Value of key \"%s\" must be integer, but \"%s\" was given", key, value);
1082  *error_string = formated_err;
1083 
1084  return (0);
1085 }
1086 
1087 static int uidgid_config_parser_cb(const char *path,
1088  char *key,
1089  char *value,
1090  enum parser_cb_type type,
1091  const char **error_string,
1092  icmap_map_t config_map,
1093  void *user_data)
1094 {
1095  char key_name[ICMAP_KEYNAME_MAXLEN];
1096  int uid, gid;
1097 
1098  switch (type) {
1099  case PARSER_CB_START:
1100  break;
1101  case PARSER_CB_END:
1102  break;
1103  case PARSER_CB_ITEM:
1104  if (strcmp(path, "uidgid.uid") == 0) {
1105  uid = uid_determine(value);
1106  if (uid == -1) {
1107  *error_string = error_string_response;
1108  return (0);
1109  }
1110  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.uid.%u",
1111  uid);
1112  icmap_set_uint8_r(config_map, key_name, 1);
1113  } else if (strcmp(path, "uidgid.gid") == 0) {
1114  gid = gid_determine(value);
1115  if (gid == -1) {
1116  *error_string = error_string_response;
1117  return (0);
1118  }
1119  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "uidgid.gid.%u",
1120  gid);
1121  icmap_set_uint8_r(config_map, key_name, 1);
1122  } else {
1123  *error_string = "uidgid: Only uid and gid are allowed items";
1124  return (0);
1125  }
1126  break;
1128  if (strcmp(path, "uidgid") != 0) {
1129  *error_string = "uidgid: Can't add subsection different then uidgid";
1130  return (0);
1131  };
1132  break;
1133  case PARSER_CB_SECTION_END:
1134  break;
1135  }
1136 
1137  return (1);
1138 }
1139 
1140 static int read_uidgid_files_into_icmap(
1141  const char **error_string,
1142  icmap_map_t config_map)
1143 {
1144  FILE *fp;
1145  const char *dirname;
1146  DIR *dp;
1147  struct dirent *dirent;
1148  struct dirent *entry;
1149  char filename[PATH_MAX + FILENAME_MAX + 1];
1150  int res = 0;
1151  size_t len;
1152  int return_code;
1153  struct stat stat_buf;
1154  char key_name[ICMAP_KEYNAME_MAXLEN];
1155 
1156  dirname = COROSYSCONFDIR "/uidgid.d";
1157  dp = opendir (dirname);
1158 
1159  if (dp == NULL)
1160  return 0;
1161 
1162  len = offsetof(struct dirent, d_name) + FILENAME_MAX + 1;
1163 
1164  entry = malloc(len);
1165  if (entry == NULL) {
1166  res = 0;
1167  goto error_exit;
1168  }
1169 
1170  for (return_code = readdir_r(dp, entry, &dirent);
1171  dirent != NULL && return_code == 0;
1172  return_code = readdir_r(dp, entry, &dirent)) {
1173 
1174  snprintf(filename, sizeof (filename), "%s/%s", dirname, dirent->d_name);
1175  res = stat (filename, &stat_buf);
1176  if (res == 0 && S_ISREG(stat_buf.st_mode)) {
1177 
1178  fp = fopen (filename, "r");
1179  if (fp == NULL) continue;
1180 
1181  key_name[0] = 0;
1182 
1183  res = parse_section(fp, key_name, error_string, 0, uidgid_config_parser_cb, config_map, NULL);
1184 
1185  fclose (fp);
1186 
1187  if (res != 0) {
1188  goto error_exit;
1189  }
1190  }
1191  }
1192 
1193 error_exit:
1194  free (entry);
1195  closedir(dp);
1196 
1197  return res;
1198 }
1199 
1200 /* Read config file and load into icmap */
1201 static int read_config_file_into_icmap(
1202  const char **error_string,
1203  icmap_map_t config_map)
1204 {
1205  FILE *fp;
1206  const char *filename;
1207  char *error_reason = error_string_response;
1208  int res;
1209  char key_name[ICMAP_KEYNAME_MAXLEN];
1210  struct main_cp_cb_data data;
1211 
1212  filename = getenv ("COROSYNC_MAIN_CONFIG_FILE");
1213  if (!filename)
1214  filename = COROSYSCONFDIR "/corosync.conf";
1215 
1216  fp = fopen (filename, "r");
1217  if (fp == NULL) {
1218  char error_str[100];
1219  const char *error_ptr = qb_strerror_r(errno, error_str, sizeof(error_str));
1220  snprintf (error_reason, sizeof(error_string_response),
1221  "Can't read file %s reason = (%s)",
1222  filename, error_ptr);
1223  *error_string = error_reason;
1224  return -1;
1225  }
1226 
1227  key_name[0] = 0;
1228 
1229  res = parse_section(fp, key_name, error_string, 0, main_config_parser_cb, config_map, &data);
1230 
1231  fclose(fp);
1232 
1233  if (res == 0) {
1234  res = read_uidgid_files_into_icmap(error_string, config_map);
1235  }
1236 
1237  if (res == 0) {
1238  snprintf (error_reason, sizeof(error_string_response),
1239  "Successfully read main configuration file '%s'.", filename);
1240  *error_string = error_reason;
1241  }
1242 
1243  return res;
1244 }