Browse code

cfg framework: group instance values can be deleted

Added support for deleting a single value from a group instance.
The value is reset to the default value in this case, it follows the
changes of the default value.

Related functions:

- cfg_del_now()
- cfg_del_delayed()

Miklos Tirpak authored on 05/01/2011 13:57:14
Showing 4 changed files
... ...
@@ -30,6 +30,7 @@
30 30
 #include "../str.h"
31 31
 
32 32
 /* variable type */
33
+#define CFG_VAR_UNSET		0U
33 34
 #define CFG_VAR_INT		1U
34 35
 #define CFG_VAR_STRING		2U
35 36
 #define CFG_VAR_STR		3U
... ...
@@ -330,6 +330,11 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
330 330
 		return -1;
331 331
 	}
332 332
 
333
+	if ((val_type == CFG_VAR_UNSET) && !group_id) {
334
+		LOG(L_ERR, "ERROR: cfg_set_now(): Only group instance values can be deleted\n");
335
+		return -1;
336
+	}
337
+
333 338
 	if (group_id && !cfg_shmized) {
334 339
 		/* The config group has not been shmized yet,
335 340
 		but an additional instance of a variable needs to be added to the group.
... ...
@@ -372,10 +377,13 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
372 377
 	}
373 378
 
374 379
 	/* check whether we have to convert the type */
375
-	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
380
+	if ((val_type != CFG_VAR_UNSET)
381
+		&& convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
382
+	)
376 383
 		goto error0;
377 384
 	
378
-	if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
385
+	if ((val_type != CFG_VAR_UNSET)
386
+	&& (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
379 387
 	&& (var->def->min || var->def->max)) {
380 388
 		/* perform a simple min-max check for integers */
381 389
 		if (((int)(long)v < var->def->min)
... ...
@@ -385,7 +393,9 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
385 393
 		}
386 394
 	}
387 395
 
388
-	if (var->def->on_change_cb) {
396
+	if ((val_type != CFG_VAR_UNSET)
397
+		&& var->def->on_change_cb
398
+	) {
389 399
 		/* Call the fixup function.
390 400
 		There is no need to set a temporary cfg handle,
391 401
 		becaue a single variable is changed */
... ...
@@ -450,6 +460,12 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
450 460
 					group_name->len, group_name->s, *group_id);
451 461
 				goto error;
452 462
 			}
463
+			if ((val_type == CFG_VAR_UNSET) && !CFG_VAR_TEST(group_inst, var)) {
464
+				/* nothing to do, the variable is not set in the group instance */
465
+				CFG_WRITER_UNLOCK();
466
+				LOG(L_DBG, "DEBUG: cfg_set_now(): The variable is not set\n");
467
+				return 0;
468
+			}
453 469
 			var_block = group_inst->vars;
454 470
 		} else {
455 471
 			group_inst = NULL;
... ...
@@ -494,37 +510,47 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
494 510
 		p = *(group->handle) + var->offset;
495 511
 	}
496 512
 
497
-	/* set the new value */
498
-	switch (CFG_VAR_TYPE(var)) {
499
-	case CFG_VAR_INT:
500
-		*(int *)p = (int)(long)v;
501
-		break;
513
+	if (val_type != CFG_VAR_UNSET) {
514
+		/* set the new value */
515
+		switch (CFG_VAR_TYPE(var)) {
516
+		case CFG_VAR_INT:
517
+			*(int *)p = (int)(long)v;
518
+			break;
502 519
 
503
-	case CFG_VAR_STRING:
504
-		/* clone the string to shm mem */
505
-		s.s = v;
506
-		s.len = (s.s) ? strlen(s.s) : 0;
507
-		if (cfg_clone_str(&s, &s)) goto error;
508
-		old_string = *(char **)p;
509
-		*(char **)p = s.s;
510
-		break;
520
+		case CFG_VAR_STRING:
521
+			/* clone the string to shm mem */
522
+			s.s = v;
523
+			s.len = (s.s) ? strlen(s.s) : 0;
524
+			if (cfg_clone_str(&s, &s)) goto error;
525
+			old_string = *(char **)p;
526
+			*(char **)p = s.s;
527
+			break;
511 528
 
512
-	case CFG_VAR_STR:
513
-		/* clone the string to shm mem */
514
-		s = *(str *)v;
515
-		if (cfg_clone_str(&s, &s)) goto error;
516
-		old_string = *(char **)p;
517
-		memcpy(p, &s, sizeof(str));
518
-		break;
529
+		case CFG_VAR_STR:
530
+			/* clone the string to shm mem */
531
+			s = *(str *)v;
532
+			if (cfg_clone_str(&s, &s)) goto error;
533
+			old_string = *(char **)p;
534
+			memcpy(p, &s, sizeof(str));
535
+			break;
519 536
 
520
-	case CFG_VAR_POINTER:
521
-		*(void **)p = v;
522
-		break;
537
+		case CFG_VAR_POINTER:
538
+			*(void **)p = v;
539
+			break;
523 540
 
541
+		}
542
+		if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
543
+			old_string = NULL; /* the string is the same as the default one,
544
+						it cannot be freed */
545
+	} else {
546
+		/* copy the default value to the group instance */
547
+		if ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
548
+		|| (CFG_VAR_TYPE(var) == CFG_VAR_STR))
549
+			old_string = *(char **)p;
550
+		memcpy(p, CFG_GROUP_DATA(*cfg_global, group) + var->offset, cfg_var_size(var)); 
551
+
552
+		CFG_VAR_TEST_AND_RESET(group_inst, var);
524 553
 	}
525
-	if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
526
-		old_string = NULL; /* the string is the same as the default one,
527
-					it cannot be freed */
528 554
 
529 555
 	if (cfg_shmized) {
530 556
 		if (!group_inst) {
... ...
@@ -593,12 +619,25 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
593 619
 			var_name->len, var_name->s,
594 620
 			(char *)val);
595 621
 
596
-	else /* str type */
622
+	else if (val_type == CFG_VAR_STR)
597 623
 		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
598 624
 			"has been changed to \"%.*s\"\n",
599 625
 			group_name->len, group_name->s,
600 626
 			var_name->len, var_name->s,
601 627
 			((str *)val)->len, ((str *)val)->s);
628
+
629
+	else if (val_type == CFG_VAR_UNSET)
630
+		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
631
+			"has been deleted\n",
632
+			group_name->len, group_name->s,
633
+			var_name->len, var_name->s);
634
+
635
+	else
636
+		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
637
+			"has been changed\n",
638
+			group_name->len, group_name->s,
639
+			var_name->len, var_name->s);
640
+
602 641
 	if (group_id)
603 642
 		LOG(L_INFO, "INFO: cfg_set_now(): group id = %u\n",
604 643
 			*group_id);
... ...
@@ -647,6 +686,14 @@ int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
647 686
 				(void *)val, CFG_VAR_STR);
648 687
 }
649 688
 
689
+/* Delete a variable from the group instance.
690
+ * wrapper function for cfg_set_now */
691
+int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
692
+{
693
+	return cfg_set_now(ctx, group_name, group_id, var_name,
694
+				NULL, CFG_VAR_UNSET);
695
+}
696
+
650 697
 /* sets the value of a variable but does not commit the change
651 698
  *
652 699
  * return value:
... ...
@@ -679,6 +726,11 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
679 726
 		return -1;
680 727
 	}
681 728
 
729
+	if ((val_type == CFG_VAR_UNSET) && !group_id) {
730
+		LOG(L_ERR, "ERROR: cfg_set_delayed(): Only group instance values can be deleted\n");
731
+		return -1;
732
+	}
733
+
682 734
 	/* look-up the group and the variable */
683 735
 	if (cfg_lookup_var(group_name, var_name, &group, &var))
684 736
 		return 1;
... ...
@@ -703,10 +755,13 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
703 755
 	}
704 756
 
705 757
 	/* check whether we have to convert the type */
706
-	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
758
+	if ((val_type != CFG_VAR_UNSET)
759
+		&& convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
760
+	)
707 761
 		goto error0;
708 762
 
709
-	if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
763
+	if ((val_type != CFG_VAR_UNSET)
764
+	&& (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
710 765
 	&& (var->def->min || var->def->max)) {
711 766
 		/* perform a simple min-max check for integers */
712 767
 		if (((int)(long)v < var->def->min)
... ...
@@ -720,7 +775,7 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
720 775
 	the list of changed variables */
721 776
 	CFG_CTX_LOCK(ctx);
722 777
 
723
-	if (var->def->on_change_cb) {
778
+	if ((val_type != CFG_VAR_UNSET) && var->def->on_change_cb) {
724 779
 		/* The fixup function must see also the
725 780
 		not yet committed values, so a temporary handle
726 781
 		must be prepared that points to the new config.
... ...
@@ -793,8 +848,9 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
793 848
 	}
794 849
 
795 850
 	/* everything went ok, we can add the new value to the list */
796
-	size = sizeof(cfg_changed_var_t) -
797
-			sizeof(((cfg_changed_var_t*)0)->new_val) + cfg_var_size(var);
851
+	size = sizeof(cfg_changed_var_t)
852
+		- sizeof(((cfg_changed_var_t*)0)->new_val)
853
+		+ ((val_type != CFG_VAR_UNSET) ? cfg_var_size(var) : 0);
798 854
 	changed = (cfg_changed_var_t *)shm_malloc(size);
799 855
 	if (!changed) {
800 856
 		LOG(L_ERR, "ERROR: cfg_set_delayed(): not enough shm memory\n");
... ...
@@ -808,31 +864,35 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
808 864
 		changed->group_id_set = 1;
809 865
 	}
810 866
 
811
-	switch (CFG_VAR_TYPE(var)) {
867
+	if (val_type != CFG_VAR_UNSET) {
868
+		switch (CFG_VAR_TYPE(var)) {
812 869
 
813
-	case CFG_VAR_INT:
814
-		changed->new_val.vint = (int)(long)v;
815
-		break;
870
+		case CFG_VAR_INT:
871
+			changed->new_val.vint = (int)(long)v;
872
+			break;
816 873
 
817
-	case CFG_VAR_STRING:
818
-		/* clone the string to shm mem */
819
-		s.s = v;
820
-		s.len = (s.s) ? strlen(s.s) : 0;
821
-		if (cfg_clone_str(&s, &s)) goto error;
822
-		changed->new_val.vp = s.s;
823
-		break;
874
+		case CFG_VAR_STRING:
875
+			/* clone the string to shm mem */
876
+			s.s = v;
877
+			s.len = (s.s) ? strlen(s.s) : 0;
878
+			if (cfg_clone_str(&s, &s)) goto error;
879
+			changed->new_val.vp = s.s;
880
+			break;
824 881
 
825
-	case CFG_VAR_STR:
826
-		/* clone the string to shm mem */
827
-		s = *(str *)v;
828
-		if (cfg_clone_str(&s, &s)) goto error;
829
-		changed->new_val.vstr=s;
830
-		break;
882
+		case CFG_VAR_STR:
883
+			/* clone the string to shm mem */
884
+			s = *(str *)v;
885
+			if (cfg_clone_str(&s, &s)) goto error;
886
+			changed->new_val.vstr=s;
887
+			break;
831 888
 
832
-	case CFG_VAR_POINTER:
833
-		changed->new_val.vp=v;
834
-		break;
889
+		case CFG_VAR_POINTER:
890
+			changed->new_val.vp=v;
891
+			break;
835 892
 
893
+		}
894
+	} else {
895
+		changed->del_value = 1;
836 896
 	}
837 897
 
838 898
 	/* Order the changes by group + group_id + original order.
... ...
@@ -877,7 +937,7 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
877 937
 			(char *)val,
878 938
 			ctx);
879 939
 
880
-	else /* str type */
940
+	else if (val_type == CFG_VAR_STR)
881 941
 		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
882 942
 			"is going to be changed to \"%.*s\" "
883 943
 			"[context=%p]\n",
... ...
@@ -885,6 +945,23 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
885 945
 			var_name->len, var_name->s,
886 946
 			((str *)val)->len, ((str *)val)->s,
887 947
 			ctx);
948
+
949
+	else if (val_type == CFG_VAR_UNSET)
950
+		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
951
+			"is going to be deleted "
952
+			"[context=%p]\n",
953
+			group_name->len, group_name->s,
954
+			var_name->len, var_name->s,
955
+			ctx);
956
+
957
+	else
958
+		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
959
+			"is going to be changed "
960
+			"[context=%p]\n",
961
+			group_name->len, group_name->s,
962
+			var_name->len, var_name->s,
963
+			ctx);
964
+
888 965
 	if (group_id)
889 966
 		LOG(L_INFO, "INFO: cfg_set_delayed(): group id = %u "
890 967
 			"[context=%p]\n",
... ...
@@ -930,6 +1007,14 @@ int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
930 1007
 				(void *)val, CFG_VAR_STR);
931 1008
 }
932 1009
 
1010
+/* Delete a variable from the group instance.
1011
+ * wrapper function for cfg_set_delayed */
1012
+int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
1013
+{
1014
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
1015
+				NULL, CFG_VAR_UNSET);
1016
+}
1017
+
933 1018
 /* commits the previously prepared changes within the context */
934 1019
 int cfg_commit(cfg_ctx_t *ctx)
935 1020
 {
... ...
@@ -1063,10 +1148,11 @@ int cfg_commit(cfg_ctx_t *ctx)
1063 1148
 			p = group_inst->vars + changed->var->offset;
1064 1149
 		}
1065 1150
 
1066
-		if (((changed->group_id_set && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1151
+		if (((changed->group_id_set && !changed->del_value && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1152
+			|| (changed->group_id_set && changed->del_value && CFG_VAR_TEST_AND_RESET(group_inst, changed->var))
1067 1153
 			|| !changed->group_id_set)
1068 1154
 		&& ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1069
-			|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) 
1155
+			|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1070 1156
 		) {
1071 1157
 			replaced[replaced_num] = *(char **)p;
1072 1158
 			if (replaced[replaced_num])
... ...
@@ -1076,9 +1162,15 @@ int cfg_commit(cfg_ctx_t *ctx)
1076 1162
 			NULL value */
1077 1163
 		}
1078 1164
 
1079
-		memcpy(	p,
1080
-			changed->new_val.vraw,
1081
-			cfg_var_size(changed->var));
1165
+		if (!changed->del_value)
1166
+			memcpy(	p,
1167
+				changed->new_val.vraw,
1168
+				cfg_var_size(changed->var));
1169
+		else
1170
+			memcpy(	p,
1171
+				CFG_GROUP_DATA(block, changed->group) + changed->var->offset,
1172
+				cfg_var_size(changed->var));
1173
+
1082 1174
 
1083 1175
 		if (!changed->group_id_set) {
1084 1176
 			/* the default value is changed, the copies of this value
... ...
@@ -1175,8 +1267,10 @@ int cfg_rollback(cfg_ctx_t *ctx)
1175 1267
 	) {
1176 1268
 		changed2 = changed->next;
1177 1269
 
1178
-		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1179
-		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
1270
+		if (!changed->del_value
1271
+			&& ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1272
+				|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1273
+		) {
1180 1274
 			if (changed->new_val.vp)
1181 1275
 				shm_free(changed->new_val.vp);
1182 1276
 		}
... ...
@@ -1345,7 +1439,7 @@ int cfg_diff_next(void **h,
1345 1439
 {
1346 1440
 	cfg_changed_var_t	*changed;
1347 1441
 	cfg_group_inst_t	*group_inst;
1348
-	union cfg_var_value* pval;
1442
+	union cfg_var_value	*pval_old, *pval_new;
1349 1443
 	static str	old_s, new_s;	/* we need the value even
1350 1444
 					after the function returns */
1351 1445
 
... ...
@@ -1362,7 +1456,7 @@ int cfg_diff_next(void **h,
1362 1456
 	It means that the variable is read from the local config
1363 1457
 	after forking */
1364 1458
 	if (!changed->group_id_set) {
1365
-		pval = (union cfg_var_value*)
1459
+		pval_old = (union cfg_var_value*)
1366 1460
 				(*(changed->group->handle) + changed->var->offset);
1367 1461
 	} else {
1368 1462
 		if (!cfg_local) {
... ...
@@ -1377,31 +1471,36 @@ int cfg_diff_next(void **h,
1377 1471
 				changed->group->name_len, changed->group->name, changed->group_id);
1378 1472
 			return -1;
1379 1473
 		}
1380
-		pval = (union cfg_var_value*)
1474
+		pval_old = (union cfg_var_value*)
1381 1475
 				(group_inst->vars + changed->var->offset);
1382 1476
 	}
1477
+	if (!changed->del_value)
1478
+		pval_new = &changed->new_val;
1479
+	else
1480
+		pval_new = (union cfg_var_value*)
1481
+				(*(changed->group->handle) + changed->var->offset);
1383 1482
 
1384 1483
 	switch (CFG_VAR_TYPE(changed->var)) {
1385 1484
 	case CFG_VAR_INT:
1386
-		*old_val = (void *)(long)pval->vint;
1387
-		*new_val = (void *)(long)changed->new_val.vint;
1485
+		*old_val = (void *)(long)pval_old->vint;
1486
+		*new_val = (void *)(long)pval_new->vint;
1388 1487
 		break;
1389 1488
 
1390 1489
 	case CFG_VAR_STRING:
1391
-		*old_val = pval->vp;
1392
-		*new_val = changed->new_val.vp;
1490
+		*old_val = pval_old->vp;
1491
+		*new_val = pval_new->vp;
1393 1492
 		break;
1394 1493
 
1395 1494
 	case CFG_VAR_STR:
1396
-		old_s=pval->vstr;
1495
+		old_s=pval_old->vstr;
1397 1496
 		*old_val = (void *)&old_s;
1398
-		new_s=changed->new_val.vstr;
1497
+		new_s=pval_new->vstr;
1399 1498
 		*new_val = (void *)&new_s;
1400 1499
 		break;
1401 1500
 
1402 1501
 	case CFG_VAR_POINTER:
1403
-		*old_val = pval->vp;
1404
-		*new_val = changed->new_val.vp;
1502
+		*old_val = pval_old->vp;
1503
+		*new_val = pval_new->vp;
1405 1504
 		break;
1406 1505
 
1407 1506
 	}
... ...
@@ -51,6 +51,7 @@ typedef struct _cfg_changed_var {
51 51
 
52 52
 	unsigned int	group_id; /* valid only if group_id_set==1 */
53 53
 	unsigned char	group_id_set;
54
+	unsigned char	del_value;	/* delete the value instead of setting it */
54 55
 
55 56
 	/* blob that contains the new value */
56 57
 	union cfg_var_value new_val; /* variable size */
... ...
@@ -95,6 +96,10 @@ int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
95 96
 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
96 97
 			str *val);
97 98
 
99
+/*! \brief Delete a variable from the group instance.
100
+ * wrapper function for cfg_set_now */
101
+int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name);
102
+
98 103
 /* sets the value of a variable but does not commit the change */
99 104
 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
100 105
 			void *val, unsigned int val_type);
... ...
@@ -105,6 +110,10 @@ int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_
105 110
 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
106 111
 			str *val);
107 112
 
113
+/*! \brief Delete a variable from the group instance.
114
+ * wrapper function for cfg_set_delayed */
115
+int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name);
116
+
108 117
 /*! \brief commits the previously prepared changes within the context */
109 118
 int cfg_commit(cfg_ctx_t *ctx);
110 119
 
... ...
@@ -198,6 +198,11 @@ extern int		cfg_ginst_count;
198 198
 #define CFG_VAR_TEST_AND_SET(group_inst, var) \
199 199
 	bit_test_and_set((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
200 200
 
201
+/* Test whether a variable is explicitely set in the group instance,
202
+ * or it uses the default value, and reset the flag. */
203
+#define CFG_VAR_TEST_AND_RESET(group_inst, var) \
204
+	bit_test_and_reset((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
205
+
201 206
 /* Return the group instance pointer from a handle,
202 207
  * or NULL if the handle points to the default configuration block */
203 208
 #define CFG_HANDLE_TO_GINST(h) \