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 372
 	}
373 373
 
374 374
 	/* check whether we have to convert the type */
375
-	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
375
+	if ((val_type != CFG_VAR_UNSET)
376
+		&& convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
377
+	)
376 378
 		goto error0;
377 379
 	
378
-	if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
380
+	if ((val_type != CFG_VAR_UNSET)
381
+	&& (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
379 382
 	&& (var->def->min || var->def->max)) {
380 383
 		/* perform a simple min-max check for integers */
381 384
 		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 385
 		}
386 386
 	}
387 387
 
388
-	if (var->def->on_change_cb) {
388
+	if ((val_type != CFG_VAR_UNSET)
389
+		&& var->def->on_change_cb
390
+	) {
389 391
 		/* Call the fixup function.
390 392
 		There is no need to set a temporary cfg handle,
391 393
 		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 450
 					group_name->len, group_name->s, *group_id);
451 451
 				goto error;
452 452
 			}
453
+			if ((val_type == CFG_VAR_UNSET) && !CFG_VAR_TEST(group_inst, var)) {
454
+				/* nothing to do, the variable is not set in the group instance */
455
+				CFG_WRITER_UNLOCK();
456
+				LOG(L_DBG, "DEBUG: cfg_set_now(): The variable is not set\n");
457
+				return 0;
458
+			}
453 459
 			var_block = group_inst->vars;
454 460
 		} else {
455 461
 			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 494
 		p = *(group->handle) + var->offset;
495 495
 	}
496 496
 
497
-	/* set the new value */
498
-	switch (CFG_VAR_TYPE(var)) {
499
-	case CFG_VAR_INT:
500
-		*(int *)p = (int)(long)v;
501
-		break;
497
+	if (val_type != CFG_VAR_UNSET) {
498
+		/* set the new value */
499
+		switch (CFG_VAR_TYPE(var)) {
500
+		case CFG_VAR_INT:
501
+			*(int *)p = (int)(long)v;
502
+			break;
502 503
 
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;
504
+		case CFG_VAR_STRING:
505
+			/* clone the string to shm mem */
506
+			s.s = v;
507
+			s.len = (s.s) ? strlen(s.s) : 0;
508
+			if (cfg_clone_str(&s, &s)) goto error;
509
+			old_string = *(char **)p;
510
+			*(char **)p = s.s;
511
+			break;
511 512
 
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;
513
+		case CFG_VAR_STR:
514
+			/* clone the string to shm mem */
515
+			s = *(str *)v;
516
+			if (cfg_clone_str(&s, &s)) goto error;
517
+			old_string = *(char **)p;
518
+			memcpy(p, &s, sizeof(str));
519
+			break;
519 520
 
520
-	case CFG_VAR_POINTER:
521
-		*(void **)p = v;
522
-		break;
521
+		case CFG_VAR_POINTER:
522
+			*(void **)p = v;
523
+			break;
523 524
 
525
+		}
526
+		if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
527
+			old_string = NULL; /* the string is the same as the default one,
528
+						it cannot be freed */
529
+	} else {
530
+		/* copy the default value to the group instance */
531
+		if ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
532
+		|| (CFG_VAR_TYPE(var) == CFG_VAR_STR))
533
+			old_string = *(char **)p;
534
+		memcpy(p, CFG_GROUP_DATA(*cfg_global, group) + var->offset, cfg_var_size(var)); 
535
+
536
+		CFG_VAR_TEST_AND_RESET(group_inst, var);
524 537
 	}
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 538
 
529 539
 	if (cfg_shmized) {
530 540
 		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 593
 			var_name->len, var_name->s,
594 594
 			(char *)val);
595 595
 
596
-	else /* str type */
596
+	else if (val_type == CFG_VAR_STR)
597 597
 		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
598 598
 			"has been changed to \"%.*s\"\n",
599 599
 			group_name->len, group_name->s,
600 600
 			var_name->len, var_name->s,
601 601
 			((str *)val)->len, ((str *)val)->s);
602
+
603
+	else if (val_type == CFG_VAR_UNSET)
604
+		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
605
+			"has been deleted\n",
606
+			group_name->len, group_name->s,
607
+			var_name->len, var_name->s);
608
+
609
+	else
610
+		LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
611
+			"has been changed\n",
612
+			group_name->len, group_name->s,
613
+			var_name->len, var_name->s);
614
+
602 615
 	if (group_id)
603 616
 		LOG(L_INFO, "INFO: cfg_set_now(): group id = %u\n",
604 617
 			*group_id);
... ...
@@ -647,6 +686,14 @@ int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
647 647
 				(void *)val, CFG_VAR_STR);
648 648
 }
649 649
 
650
+/* Delete a variable from the group instance.
651
+ * wrapper function for cfg_set_now */
652
+int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
653
+{
654
+	return cfg_set_now(ctx, group_name, group_id, var_name,
655
+				NULL, CFG_VAR_UNSET);
656
+}
657
+
650 658
 /* sets the value of a variable but does not commit the change
651 659
  *
652 660
  * return value:
... ...
@@ -679,6 +726,11 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
679 679
 		return -1;
680 680
 	}
681 681
 
682
+	if ((val_type == CFG_VAR_UNSET) && !group_id) {
683
+		LOG(L_ERR, "ERROR: cfg_set_delayed(): Only group instance values can be deleted\n");
684
+		return -1;
685
+	}
686
+
682 687
 	/* look-up the group and the variable */
683 688
 	if (cfg_lookup_var(group_name, var_name, &group, &var))
684 689
 		return 1;
... ...
@@ -703,10 +755,13 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
703 703
 	}
704 704
 
705 705
 	/* check whether we have to convert the type */
706
-	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
706
+	if ((val_type != CFG_VAR_UNSET)
707
+		&& convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
708
+	)
707 709
 		goto error0;
708 710
 
709
-	if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
711
+	if ((val_type != CFG_VAR_UNSET)
712
+	&& (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
710 713
 	&& (var->def->min || var->def->max)) {
711 714
 		/* perform a simple min-max check for integers */
712 715
 		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 720
 	the list of changed variables */
721 721
 	CFG_CTX_LOCK(ctx);
722 722
 
723
-	if (var->def->on_change_cb) {
723
+	if ((val_type != CFG_VAR_UNSET) && var->def->on_change_cb) {
724 724
 		/* The fixup function must see also the
725 725
 		not yet committed values, so a temporary handle
726 726
 		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 793
 	}
794 794
 
795 795
 	/* 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);
796
+	size = sizeof(cfg_changed_var_t)
797
+		- sizeof(((cfg_changed_var_t*)0)->new_val)
798
+		+ ((val_type != CFG_VAR_UNSET) ? cfg_var_size(var) : 0);
798 799
 	changed = (cfg_changed_var_t *)shm_malloc(size);
799 800
 	if (!changed) {
800 801
 		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 808
 		changed->group_id_set = 1;
809 809
 	}
810 810
 
811
-	switch (CFG_VAR_TYPE(var)) {
811
+	if (val_type != CFG_VAR_UNSET) {
812
+		switch (CFG_VAR_TYPE(var)) {
812 813
 
813
-	case CFG_VAR_INT:
814
-		changed->new_val.vint = (int)(long)v;
815
-		break;
814
+		case CFG_VAR_INT:
815
+			changed->new_val.vint = (int)(long)v;
816
+			break;
816 817
 
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;
818
+		case CFG_VAR_STRING:
819
+			/* clone the string to shm mem */
820
+			s.s = v;
821
+			s.len = (s.s) ? strlen(s.s) : 0;
822
+			if (cfg_clone_str(&s, &s)) goto error;
823
+			changed->new_val.vp = s.s;
824
+			break;
824 825
 
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;
826
+		case CFG_VAR_STR:
827
+			/* clone the string to shm mem */
828
+			s = *(str *)v;
829
+			if (cfg_clone_str(&s, &s)) goto error;
830
+			changed->new_val.vstr=s;
831
+			break;
831 832
 
832
-	case CFG_VAR_POINTER:
833
-		changed->new_val.vp=v;
834
-		break;
833
+		case CFG_VAR_POINTER:
834
+			changed->new_val.vp=v;
835
+			break;
835 836
 
837
+		}
838
+	} else {
839
+		changed->del_value = 1;
836 840
 	}
837 841
 
838 842
 	/* 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 877
 			(char *)val,
878 878
 			ctx);
879 879
 
880
-	else /* str type */
880
+	else if (val_type == CFG_VAR_STR)
881 881
 		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
882 882
 			"is going to be changed to \"%.*s\" "
883 883
 			"[context=%p]\n",
... ...
@@ -885,6 +945,23 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str
885 885
 			var_name->len, var_name->s,
886 886
 			((str *)val)->len, ((str *)val)->s,
887 887
 			ctx);
888
+
889
+	else if (val_type == CFG_VAR_UNSET)
890
+		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
891
+			"is going to be deleted "
892
+			"[context=%p]\n",
893
+			group_name->len, group_name->s,
894
+			var_name->len, var_name->s,
895
+			ctx);
896
+
897
+	else
898
+		LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
899
+			"is going to be changed "
900
+			"[context=%p]\n",
901
+			group_name->len, group_name->s,
902
+			var_name->len, var_name->s,
903
+			ctx);
904
+
888 905
 	if (group_id)
889 906
 		LOG(L_INFO, "INFO: cfg_set_delayed(): group id = %u "
890 907
 			"[context=%p]\n",
... ...
@@ -930,6 +1007,14 @@ int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
930 930
 				(void *)val, CFG_VAR_STR);
931 931
 }
932 932
 
933
+/* Delete a variable from the group instance.
934
+ * wrapper function for cfg_set_delayed */
935
+int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
936
+{
937
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
938
+				NULL, CFG_VAR_UNSET);
939
+}
940
+
933 941
 /* commits the previously prepared changes within the context */
934 942
 int cfg_commit(cfg_ctx_t *ctx)
935 943
 {
... ...
@@ -1063,10 +1148,11 @@ int cfg_commit(cfg_ctx_t *ctx)
1063 1063
 			p = group_inst->vars + changed->var->offset;
1064 1064
 		}
1065 1065
 
1066
-		if (((changed->group_id_set && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1066
+		if (((changed->group_id_set && !changed->del_value && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1067
+			|| (changed->group_id_set && changed->del_value && CFG_VAR_TEST_AND_RESET(group_inst, changed->var))
1067 1068
 			|| !changed->group_id_set)
1068 1069
 		&& ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1069
-			|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) 
1070
+			|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1070 1071
 		) {
1071 1072
 			replaced[replaced_num] = *(char **)p;
1072 1073
 			if (replaced[replaced_num])
... ...
@@ -1076,9 +1162,15 @@ int cfg_commit(cfg_ctx_t *ctx)
1076 1076
 			NULL value */
1077 1077
 		}
1078 1078
 
1079
-		memcpy(	p,
1080
-			changed->new_val.vraw,
1081
-			cfg_var_size(changed->var));
1079
+		if (!changed->del_value)
1080
+			memcpy(	p,
1081
+				changed->new_val.vraw,
1082
+				cfg_var_size(changed->var));
1083
+		else
1084
+			memcpy(	p,
1085
+				CFG_GROUP_DATA(block, changed->group) + changed->var->offset,
1086
+				cfg_var_size(changed->var));
1087
+
1082 1088
 
1083 1089
 		if (!changed->group_id_set) {
1084 1090
 			/* the default value is changed, the copies of this value
... ...
@@ -1175,8 +1267,10 @@ int cfg_rollback(cfg_ctx_t *ctx)
1175 1175
 	) {
1176 1176
 		changed2 = changed->next;
1177 1177
 
1178
-		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1179
-		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
1178
+		if (!changed->del_value
1179
+			&& ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1180
+				|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1181
+		) {
1180 1182
 			if (changed->new_val.vp)
1181 1183
 				shm_free(changed->new_val.vp);
1182 1184
 		}
... ...
@@ -1345,7 +1439,7 @@ int cfg_diff_next(void **h,
1345 1345
 {
1346 1346
 	cfg_changed_var_t	*changed;
1347 1347
 	cfg_group_inst_t	*group_inst;
1348
-	union cfg_var_value* pval;
1348
+	union cfg_var_value	*pval_old, *pval_new;
1349 1349
 	static str	old_s, new_s;	/* we need the value even
1350 1350
 					after the function returns */
1351 1351
 
... ...
@@ -1362,7 +1456,7 @@ int cfg_diff_next(void **h,
1362 1362
 	It means that the variable is read from the local config
1363 1363
 	after forking */
1364 1364
 	if (!changed->group_id_set) {
1365
-		pval = (union cfg_var_value*)
1365
+		pval_old = (union cfg_var_value*)
1366 1366
 				(*(changed->group->handle) + changed->var->offset);
1367 1367
 	} else {
1368 1368
 		if (!cfg_local) {
... ...
@@ -1377,31 +1471,36 @@ int cfg_diff_next(void **h,
1377 1377
 				changed->group->name_len, changed->group->name, changed->group_id);
1378 1378
 			return -1;
1379 1379
 		}
1380
-		pval = (union cfg_var_value*)
1380
+		pval_old = (union cfg_var_value*)
1381 1381
 				(group_inst->vars + changed->var->offset);
1382 1382
 	}
1383
+	if (!changed->del_value)
1384
+		pval_new = &changed->new_val;
1385
+	else
1386
+		pval_new = (union cfg_var_value*)
1387
+				(*(changed->group->handle) + changed->var->offset);
1383 1388
 
1384 1389
 	switch (CFG_VAR_TYPE(changed->var)) {
1385 1390
 	case CFG_VAR_INT:
1386
-		*old_val = (void *)(long)pval->vint;
1387
-		*new_val = (void *)(long)changed->new_val.vint;
1391
+		*old_val = (void *)(long)pval_old->vint;
1392
+		*new_val = (void *)(long)pval_new->vint;
1388 1393
 		break;
1389 1394
 
1390 1395
 	case CFG_VAR_STRING:
1391
-		*old_val = pval->vp;
1392
-		*new_val = changed->new_val.vp;
1396
+		*old_val = pval_old->vp;
1397
+		*new_val = pval_new->vp;
1393 1398
 		break;
1394 1399
 
1395 1400
 	case CFG_VAR_STR:
1396
-		old_s=pval->vstr;
1401
+		old_s=pval_old->vstr;
1397 1402
 		*old_val = (void *)&old_s;
1398
-		new_s=changed->new_val.vstr;
1403
+		new_s=pval_new->vstr;
1399 1404
 		*new_val = (void *)&new_s;
1400 1405
 		break;
1401 1406
 
1402 1407
 	case CFG_VAR_POINTER:
1403
-		*old_val = pval->vp;
1404
-		*new_val = changed->new_val.vp;
1408
+		*old_val = pval_old->vp;
1409
+		*new_val = pval_new->vp;
1405 1410
 		break;
1406 1411
 
1407 1412
 	}
... ...
@@ -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 95
 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
96 96
 			str *val);
97 97
 
98
+/*! \brief Delete a variable from the group instance.
99
+ * wrapper function for cfg_set_now */
100
+int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name);
101
+
98 102
 /* sets the value of a variable but does not commit the change */
99 103
 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
100 104
 			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 105
 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
106 106
 			str *val);
107 107
 
108
+/*! \brief Delete a variable from the group instance.
109
+ * wrapper function for cfg_set_delayed */
110
+int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name);
111
+
108 112
 /*! \brief commits the previously prepared changes within the context */
109 113
 int cfg_commit(cfg_ctx_t *ctx);
110 114
 
... ...
@@ -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) \