Browse code

cfg framework: apply the additional variable list

The additional variable list which is linked to the groups
is applied when the config is shmized. During this process,
the array of group instances is created, the values are fixed-up,
the changes are applied to each instance, and the list is freed.
Any change after the config is shmized is directly made in the
memory block as opposed to using the list.
(The list is necessary at the beginning because not even shm_malloc
is available, and the number of group instances is not known.)

Miklos Tirpak authored on 28/09/2010 09:44:29
Showing 4 changed files
... ...
@@ -1595,3 +1595,178 @@ error:
1595 1595
 
1596 1596
 	return -1;
1597 1597
 }
1598
+
1599
+/* Apply the changes to a group instance as long as the additional variable
1600
+ * belongs to the specified group_id. *add_var_p is moved to the next additional
1601
+ * variable, and all the consumed variables are freed.
1602
+ * This function can be used only during the cfg shmize process.
1603
+ * For internal use only!
1604
+ */
1605
+int cfg_apply_list(cfg_group_inst_t *ginst, cfg_group_t *group,
1606
+			unsigned int group_id, cfg_add_var_t **add_var_p)
1607
+{
1608
+	cfg_add_var_t	*add_var;
1609
+	cfg_mapping_t	*var;
1610
+	void		*val, *v, *p;
1611
+	str		group_name, var_name, s;
1612
+	char		*old_string;
1613
+
1614
+	group_name.s = group->name;
1615
+	group_name.len = group->name_len;
1616
+	while (*add_var_p && ((*add_var_p)->group_id == group_id)) {
1617
+		add_var = *add_var_p;
1618
+
1619
+		if (add_var->type == 0)
1620
+			goto done; /* Nothing needs to be changed,
1621
+				this additional variable only forces a new
1622
+				group instance to be created. */
1623
+		var_name.s = add_var->name;
1624
+		var_name.len = add_var->name_len;
1625
+
1626
+		if (!(var = cfg_lookup_var2(group, add_var->name, add_var->name_len))) {
1627
+			LOG(L_ERR, "ERROR: cfg_apply_list(): Variable is not found: %.*s.%.*s\n",
1628
+				group->name_len, group->name,
1629
+				add_var->name_len, add_var->name);
1630
+			goto error;
1631
+		}
1632
+
1633
+		/* check whether the variable is read-only */
1634
+		if (var->def->type & CFG_READONLY) {
1635
+			LOG(L_ERR, "ERROR: cfg_apply_list(): variable is read-only\n");
1636
+			goto error;
1637
+		}
1638
+
1639
+		/* The additional variable instances having per-child process callback
1640
+		 * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
1641
+		 * The reason is that such variables typically set global parameters
1642
+		 * as opposed to per-process variables. Hence, it is not possible to set
1643
+		 * the group handle temporary to another block, and then reset it back later. */
1644
+		if (var->def->on_set_child_cb
1645
+			&& var->def->type & CFG_CB_ONLY_ONCE
1646
+		) {
1647
+			LOG(L_ERR, "ERROR: cfg_apply_list(): This variable does not support muliple values.\n");
1648
+			goto error;
1649
+		}
1650
+
1651
+		switch(add_var->type) {
1652
+		case CFG_VAR_INT:
1653
+			val = (void *)(long)add_var->val.i;
1654
+			break;
1655
+		case CFG_VAR_STR:
1656
+			val = (str *)&(add_var->val.s);
1657
+			break;
1658
+		case CFG_VAR_STRING:
1659
+			val = (char *)add_var->val.ch;
1660
+			break;
1661
+		default:
1662
+			LOG(L_ERR, "ERROR: cfg_apply_list(): unsupported variable type: %d\n",
1663
+				add_var->type);
1664
+			goto error;
1665
+		}
1666
+		/* check whether we have to convert the type */
1667
+		if (convert_val(add_var->type, val, CFG_INPUT_TYPE(var), &v))
1668
+			goto error;
1669
+
1670
+		if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
1671
+		&& (var->def->min || var->def->max)) {
1672
+			/* perform a simple min-max check for integers */
1673
+			if (((int)(long)v < var->def->min)
1674
+			|| ((int)(long)v > var->def->max)) {
1675
+				LOG(L_ERR, "ERROR: cfg_apply_list(): integer value is out of range\n");
1676
+				goto error;
1677
+			}
1678
+		}
1679
+
1680
+		if (var->def->on_change_cb) {
1681
+			/* Call the fixup function.
1682
+			The handle can point to the variables of the group instance. */
1683
+			if (var->def->on_change_cb(ginst->vars,
1684
+							&group_name,
1685
+							&var_name,
1686
+							&v) < 0) {
1687
+				LOG(L_ERR, "ERROR: cfg_apply_list(): fixup failed\n");
1688
+				goto error;
1689
+			}
1690
+		}
1691
+
1692
+		p = ginst->vars + var->offset;
1693
+		old_string = NULL;
1694
+		/* set the new value */
1695
+		switch (CFG_VAR_TYPE(var)) {
1696
+		case CFG_VAR_INT:
1697
+			*(int *)p = (int)(long)v;
1698
+			break;
1699
+
1700
+		case CFG_VAR_STRING:
1701
+			/* clone the string to shm mem */
1702
+			s.s = v;
1703
+			s.len = (s.s) ? strlen(s.s) : 0;
1704
+			if (cfg_clone_str(&s, &s)) goto error;
1705
+			old_string = *(char **)p;
1706
+			*(char **)p = s.s;
1707
+			break;
1708
+
1709
+		case CFG_VAR_STR:
1710
+			/* clone the string to shm mem */
1711
+			s = *(str *)v;
1712
+			if (cfg_clone_str(&s, &s)) goto error;
1713
+			old_string = *(char **)p;
1714
+			memcpy(p, &s, sizeof(str));
1715
+			break;
1716
+
1717
+		case CFG_VAR_POINTER:
1718
+			*(void **)p = v;
1719
+			break;
1720
+
1721
+		}
1722
+		if (CFG_VAR_TEST_AND_SET(ginst, var) && old_string)
1723
+			shm_free(old_string); /* the string was already in shm memory,
1724
+					it needs to be freed.
1725
+					This can happen when the same variable is set
1726
+					multiple times before forking. */
1727
+
1728
+		if (add_var->type == CFG_VAR_INT)
1729
+			LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1730
+				"has been set to %d\n",
1731
+				group_name.len, group_name.s,
1732
+				group_id,
1733
+				var_name.len, var_name.s,
1734
+				(int)(long)val);
1735
+
1736
+		else if (add_var->type == CFG_VAR_STRING)
1737
+			LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1738
+				"has been set to \"%s\"\n",
1739
+				group_name.len, group_name.s,
1740
+				group_id,
1741
+				var_name.len, var_name.s,
1742
+				(char *)val);
1743
+
1744
+		else /* str type */
1745
+			LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1746
+				"has been set to \"%.*s\"\n",
1747
+				group_name.len, group_name.s,
1748
+				group_id,
1749
+				var_name.len, var_name.s,
1750
+				((str *)val)->len, ((str *)val)->s);
1751
+
1752
+		convert_val_cleanup();
1753
+
1754
+done:
1755
+		*add_var_p = add_var->next;
1756
+
1757
+		if ((add_var->type == CFG_VAR_STR) && add_var->val.s.s)
1758
+			pkg_free(add_var->val.s.s);
1759
+		else if ((add_var->type == CFG_VAR_STRING) && add_var->val.ch)
1760
+			pkg_free(add_var->val.ch);
1761
+		pkg_free(add_var);
1762
+	}
1763
+	return 0;
1764
+
1765
+error:
1766
+	LOG(L_ERR, "ERROR: cfg_apply_list(): Failed to set the value for: %.*s[%u].%.*s\n",
1767
+		group->name_len, group->name,
1768
+		group_id,
1769
+		add_var->name_len, add_var->name);
1770
+	convert_val_cleanup();
1771
+	return -1;
1772
+}
... ...
@@ -194,4 +194,11 @@ int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id);
194 194
 /* Delete an instance of a group */
195 195
 int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id);
196 196
 
197
+/* Apply the changes to a group instance as long as the additional variable
198
+ * belongs to the specified group_id. *add_var_p is moved to the next additional
199
+ * variable, and all the consumed variables are freed.
200
+ */
201
+int cfg_apply_list(cfg_group_inst_t *ginst, cfg_group_t *group,
202
+			unsigned int group_id, cfg_add_var_t **add_var_p);
203
+
197 204
 #endif /* _CFG_CTX_H */
... ...
@@ -59,6 +59,7 @@ cfg_child_cb_t	*cfg_child_cb = NULL;	/* pointer to the previously executed cb */
59 59
 
60 60
 /* forward declarations */
61 61
 static void del_add_var_list(cfg_group_t *group);
62
+static int apply_add_var_list(cfg_block_t *block, cfg_group_t *group);
62 63
 
63 64
 /* creates a new cfg group, and adds it to the linked list */
64 65
 cfg_group_t *cfg_new_group(char *name, int name_len,
... ...
@@ -255,6 +256,11 @@ int cfg_shmize(void)
255 256
 			goto error;
256 257
 		}
257 258
 	}
259
+	/* Create the additional group instances with applying
260
+	the temporary list. */
261
+	if (apply_add_var_list(block, group))
262
+		goto error;
263
+
258 264
 	/* try to fixup the selects that failed to be fixed-up previously */
259 265
 	if (cfg_fixup_selects()) goto error;
260 266
 
... ...
@@ -587,6 +593,29 @@ int cfg_lookup_var(str *gname, str *vname,
587 593
 	return -1;
588 594
 }
589 595
 
596
+/* searches a variable definition within a group by its name */
597
+cfg_mapping_t *cfg_lookup_var2(cfg_group_t *group, char *name, int len)
598
+{
599
+	int	i;
600
+
601
+	if (!group->mapping) return NULL; /* dynamic group is not ready */
602
+
603
+	for (	i = 0;
604
+		i < group->num;
605
+		i++
606
+	) {
607
+		if ((group->mapping[i].name_len == len)
608
+		&& (memcmp(group->mapping[i].def->name, name, len)==0)) {
609
+			return &(group->mapping[i]);
610
+		}
611
+	}
612
+
613
+	LOG(L_DBG, "DEBUG: cfg_lookup_var2(): variable not found: %.*s.%.*s\n",
614
+			group->name_len, group->name,
615
+			len, name);
616
+	return NULL;
617
+}
618
+
590 619
 /* clones the global config block
591 620
  * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
592 621
  */
... ...
@@ -941,7 +970,8 @@ error:
941 970
 }
942 971
 
943 972
 /* delete the additional variable list */
944
-static void del_add_var_list(cfg_group_t *group) {
973
+static void del_add_var_list(cfg_group_t *group)
974
+{
945 975
 	cfg_add_var_t	*add_var, *add_var2;
946 976
 
947 977
 	add_var = group->add_var;
... ...
@@ -956,3 +986,73 @@ static void del_add_var_list(cfg_group_t *group) {
956 986
 	}
957 987
 	group->add_var = NULL;
958 988
 }
989
+
990
+/* create the array of additional group instances from the linked list */
991
+static int apply_add_var_list(cfg_block_t *block, cfg_group_t *group)
992
+{
993
+	int		i, num, size;
994
+	unsigned int	group_id;
995
+	cfg_add_var_t	*add_var;
996
+	cfg_group_inst_t	*new_array, *ginst;
997
+
998
+	/* count the number of group instances */
999
+	for (	add_var = group->add_var, num = 0, group_id = 0;
1000
+		add_var;
1001
+		add_var = add_var->next
1002
+	) {
1003
+		if (!num || (group_id != add_var->group_id)) {
1004
+			num++;
1005
+			group_id = add_var->group_id;
1006
+		}
1007
+	}
1008
+
1009
+	if (!num)	/* nothing to do */
1010
+		return 0;
1011
+
1012
+	LOG(L_DBG, "DEBUG: apply_add_var_list(): creating the group instance array "
1013
+		"for '%.*s' with %d slots\n",
1014
+		group->name_len, group->name, num);
1015
+	size = (sizeof(cfg_group_inst_t) + group->size - 1) * num;
1016
+	new_array = (cfg_group_inst_t *)shm_malloc(size);
1017
+	if (!new_array) {
1018
+		LOG(L_ERR, "ERROR: apply_add_var_list(): not enough shm memory\n");
1019
+		return -1;
1020
+	}
1021
+	memset(new_array, 0, size);
1022
+
1023
+	for (i = 0; i < num; i++) {
1024
+		/* Go though each group instance, set the default values,
1025
+		and apply the changes */
1026
+
1027
+		if (!group->add_var) {
1028
+			LOG(L_ERR, "BUG: apply_add_var_list(): no more additional variable left\n");
1029
+			goto error;
1030
+		}
1031
+		ginst = (cfg_group_inst_t *)((char*)new_array + (sizeof(cfg_group_inst_t) + group->size - 1) * i);
1032
+		ginst->id = group->add_var->group_id;
1033
+		/* fill in the new group instance with the default data */
1034
+		memcpy(	ginst->vars,
1035
+			CFG_GROUP_DATA(block, group),
1036
+			group->size);
1037
+		/* cfg_apply_list() moves the group->add_var pointer to
1038
+		the beginning of the new group instance. */
1039
+		if (cfg_apply_list(ginst, group, ginst->id, &group->add_var))
1040
+			goto error;
1041
+	}
1042
+
1043
+#ifdef EXTRA_DEBUG
1044
+	if (group->add_var) {
1045
+		LOG(L_ERR, "BUG: apply_add_var_list(): not all the additional variables have been consumed\n");
1046
+		goto error;
1047
+	}
1048
+#endif
1049
+
1050
+	CFG_GROUP_META(block, group)->num = num;
1051
+	CFG_GROUP_META(block, group)->array = new_array;
1052
+	return 0;
1053
+
1054
+error:
1055
+	LOG(L_ERR, "ERROR: apply_add_var_list(): Failed to apply the additional variable list\n");
1056
+	shm_free(new_array);
1057
+	return -1;
1058
+}
... ...
@@ -382,6 +382,9 @@ cfg_group_t *cfg_lookup_group(char *name, int len);
382 382
 int cfg_lookup_var(str *gname, str *vname,
383 383
 			cfg_group_t **group, cfg_mapping_t **var);
384 384
 
385
+/* searches a variable definition within a group by its name */
386
+cfg_mapping_t *cfg_lookup_var2(cfg_group_t *group, char *name, int len);
387
+
385 388
 /* clones the global config block
386 389
  * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
387 390
  */