示例#1
0
static void create_object(confdb_handle_t handle, char * name_pt)
{
	char * obj_name_pt;
	char * save_pt;
	hdb_handle_t obj_handle;
	hdb_handle_t parent_object_handle = OBJECT_PARENT_HANDLE;
	char tmp_name[OBJ_NAME_SIZE];
	cs_error_t res;

	strncpy (tmp_name, name_pt, sizeof (tmp_name));
	tmp_name[sizeof (tmp_name) - 1] = '\0';
	obj_name_pt = strtok_r(tmp_name, SEPERATOR_STR, &save_pt);

	while (obj_name_pt != NULL) {
		res = confdb_object_find_start(handle, parent_object_handle);
		if (res != CS_OK) {
			fprintf (stderr, "Could not start object_find %d\n", res);
			exit (EXIT_FAILURE);
		}

		res = confdb_object_find(handle, parent_object_handle,
			 obj_name_pt, strlen (obj_name_pt), &obj_handle);
		if (res != CS_OK) {

			if (validate_name(obj_name_pt) != CS_OK) {
				fprintf(stderr, "Incorrect object name \"%s\", \"=\" not allowed.\n",
						obj_name_pt);
				exit(EXIT_FAILURE);
			}

			if (debug)
				printf ("%s:%d: %s\n", __func__,__LINE__, obj_name_pt);
			res = confdb_object_create (handle,
										parent_object_handle,
										obj_name_pt,
										strlen (obj_name_pt),
										&obj_handle);
			if (res != CS_OK)
				fprintf(stderr, "Failed to create object \"%s\". Error %d.\n",
						obj_name_pt, res);
		}

		parent_object_handle = obj_handle;
		obj_name_pt = strtok_r (NULL, SEPERATOR_STR, &save_pt);
	}
}
示例#2
0
文件: join.c 项目: smintz/cluster
int join(commandline_t *comline, char *main_envp[])
{
	int i, err;
	int envptr = 0;
	int argvptr = 0;
	char scratch[1024];
	char config_modules[1024];
	cman_handle_t h = NULL;
	int status;
	hdb_handle_t object_handle;
	confdb_handle_t confdb_handle;
	int res;
	pid_t corosync_pid;
	int p[2];
	confdb_callbacks_t callbacks = {
		.confdb_key_change_notify_fn = NULL,
		.confdb_object_create_change_notify_fn = NULL,
		.confdb_object_delete_change_notify_fn = NULL
	};

        /*
	 * If we can talk to cman then we're already joined (or joining);
	 */
	h = cman_admin_init(NULL);
	if (h)
		die("Node is already active");

	/* Set up environment variables for override */
	if (comline->multicast_addr) {
		snprintf(scratch, sizeof(scratch), "CMAN_MCAST_ADDR=%s", comline->multicast_addr);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->votes_opt) {
		snprintf(scratch, sizeof(scratch), "CMAN_VOTES=%d", comline->votes);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->expected_votes_opt) {
		snprintf(scratch, sizeof(scratch), "CMAN_EXPECTEDVOTES=%d", comline->expected_votes);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->port) {
		snprintf(scratch, sizeof(scratch), "CMAN_IP_PORT=%d", comline->port);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->nodeid) {
		snprintf(scratch, sizeof(scratch), "CMAN_NODEID=%d", comline->nodeid);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->clustername_opt) {
		snprintf(scratch, sizeof(scratch), "CMAN_CLUSTER_NAME=%s", comline->clustername);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->nodenames[0]) {
		snprintf(scratch, sizeof(scratch), "CMAN_NODENAME=%s", comline->nodenames[0]);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->key_filename) {
		snprintf(scratch, sizeof(scratch), "CMAN_KEYFILE=%s", comline->key_filename);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->two_node) {
		snprintf(scratch, sizeof(scratch), "CMAN_2NODE=true");
		envp[envptr++] = strdup(scratch);
	}
	if (comline->verbose ^ DEBUG_STARTUP_ONLY) {
		snprintf(scratch, sizeof(scratch), "CMAN_DEBUG=%d", comline->verbose);
		envp[envptr++] = strdup(scratch);
	}
	if (comline->nostderr_debug) {
		snprintf(scratch, sizeof(scratch), "CMAN_NOSTDERR_DEBUG=true");
		envp[envptr++] = strdup(scratch);
	}
	if (comline->noconfig_opt) {
		envp[envptr++] = strdup("CMAN_NOCONFIG=true");
		snprintf(config_modules, sizeof(config_modules), "cmanpreconfig");
	}
	else {
		snprintf(config_modules, sizeof(config_modules), "%s:cmanpreconfig", comline->config_lcrso);
	}
	if (comline->noopenais_opt) {
		envp[envptr++] = strdup("CMAN_NOOPENAIS=true");
	}

	snprintf(scratch, sizeof(scratch), "COROSYNC_DEFAULT_CONFIG_IFACE=%s", config_modules);
	envp[envptr++] = strdup(scratch);

	/* Copy any COROSYNC_* env variables to the new daemon */
	i=0;
	while (i < MAX_ARGS && main_envp[i]) {
		if (strncmp(main_envp[i], "COROSYNC_", 9) == 0)
			envp[envptr++] = main_envp[i];
		i++;
	}


	/* Create a pipe to monitor cman startup progress */
	if (pipe(p) < 0)
		die("unable to create pipe: %s", strerror(errno));
	fcntl(p[1], F_SETFD, 0); /* Don't close on exec */
	snprintf(scratch, sizeof(scratch), "CMAN_PIPE=%d", p[1]);
	envp[envptr++] = strdup(scratch);
	envp[envptr++] = NULL;

	/* Always run corosync -f because we have already forked twice anyway, and
	   we want to return any exit code that might happen */
	/* also strdup strings because it's otherwise virtually impossible to fix
	 * build warnings due to the way argv C implementation is done */
	argv[0] = strdup("corosync");
	argv[++argvptr] = strdup("-f");
	if (comline->nosetpri_opt)
		argv[++argvptr] = strdup("-p");
	argv[++argvptr] = NULL;

	/* Fork/exec cman */
	switch ( (corosync_pid = fork()) )
	{
	case -1:
		die("fork of corosync daemon failed: %s", strerror(errno));

	case 0: /* child */
		close(p[0]);
		if (comline->verbose & DEBUG_STARTUP_ONLY) {
			fprintf(stderr, "Starting %s", COROSYNCBIN);
			for (i=0; i< argvptr; i++) {
				fprintf(stderr, " %s", argv[i]);
			}
			fprintf(stderr, "\n");
			for (i=0; i<envptr-1; i++) {
				fprintf(stderr, "%s\n", envp[i]);
			}
		}
		be_daemon();

		sprintf(scratch, "FORKED: %d\n", getpid());
		err = write(p[1], scratch, strlen(scratch));

		execve(COROSYNCBIN, argv, envp);

		/* exec failed - tell the parent process */
		sprintf(scratch, "execve of " COROSYNCBIN " failed: %s", strerror(errno));
		err = write(p[1], scratch, strlen(scratch));
		exit(1);
		break;

	default: /* parent */
		break;

	}

	/* Give the daemon a chance to start up, and monitor the pipe FD for messages */
	i = 0;
	close(p[1]);

	/* Wait for the process to start or die */
	sleep(1);
	do {
		fd_set fds;
		struct timeval tv={1, 0};
		char message[1024];
		char *messageptr = message;

		FD_ZERO(&fds);
		FD_SET(p[0], &fds);

		status = select(p[0]+1, &fds, NULL, NULL, &tv);

		/* Did we get a cman-reported error? */
		if (status == 1) {
			int len;
			if ((len = read(p[0], message, sizeof(message)) > 0)) {

				/* Forked OK - get the real corosync pid */
				if (sscanf(messageptr, "FORKED: %d", &corosync_pid) == 1) {
					if (comline->verbose & DEBUG_STARTUP_ONLY)
						fprintf(stderr, "forked process ID is %d\n", corosync_pid);
					status = 0;

					/* There might be a SUCCESS or error message in the pipe too. */
					messageptr = strchr(messageptr, '\n');
					if (messageptr && strlen(messageptr) > 1)
						messageptr++;
					else
						continue;
				}
				/* Success! get the new PID of double-forked corosync */
				if (sscanf(messageptr, "SUCCESS: %d", &corosync_pid) == 1) {
					if (comline->verbose & DEBUG_STARTUP_ONLY)
						fprintf(stderr, "corosync running, process ID is %d\n", corosync_pid);
					status = 0;
					break;
				}
				else if (messageptr) {
						fprintf(stderr, "%s\n", messageptr);
						status = 1;
						break;
					}
			}
			else if (len < 0 && errno == EINTR) {
				continue;
			}
			else { /* Error or EOF - check the child status */
				status = check_corosync_status(corosync_pid);
				if (status == 0)
					break;
			}
		}

	} while (status == 0);
	close(p[0]);

	/* If corosync has started, try to connect to cman ... if it's still there */
	if (status == 0) {
		do {
			if (status == 0) {
				if (kill(corosync_pid, 0) < 0) {
					status = check_corosync_status(corosync_pid);
					die("corosync died during startup\n");
				}

				h = cman_admin_init(NULL);
				if (!h && comline->verbose & DEBUG_STARTUP_ONLY)
				{
					fprintf(stderr, "waiting for cman to start\n");
					status = check_corosync_status(corosync_pid);
				}
			}
			sleep (1);
		} while (!h && ++i < 100);
	}

	if (!h)
		die("corosync daemon didn't start");

	if ((comline->verbose & DEBUG_STARTUP_ONLY) && !cman_is_active(h))
		fprintf(stderr, "corosync started, but not joined the cluster yet.\n");

	cman_finish(h);

	/* Copy all COROSYNC_* environment variables into objdb so they can be used to validate new configurations later */
	res = confdb_initialize (&confdb_handle, &callbacks);
	if (res != CS_OK)
		goto join_exit;

	res = confdb_object_create(confdb_handle, OBJECT_PARENT_HANDLE, "cman_private", strlen("cman_private"), &object_handle);
	if (res == CS_OK) {
		int envnum = 0;
		const char *envvar = main_envp[envnum];
		const char *equal;
		char envname[PATH_MAX];


		while (envvar) {
			if (strncmp("COROSYNC_", envvar, 9) == 0) {
				equal = strchr(envvar, '=');
				if (equal) {
				        strncpy(envname, envvar, PATH_MAX);
					if (equal-envvar < PATH_MAX) {
					    envname[equal-envvar] = '\0';

					    res = confdb_key_create_typed(confdb_handle, object_handle, envname,
									  equal+1, strlen(equal+1),CONFDB_VALUETYPE_STRING);
					}
				}
			}
			envvar = main_envp[++envnum];
		}
	}
	res = confdb_key_create_typed(confdb_handle, object_handle,
				      "COROSYNC_DEFAULT_CONFIG_IFACE",
				      config_modules, strlen(config_modules), CONFDB_VALUETYPE_STRING);
	confdb_finalize (confdb_handle);

join_exit:
	return 0;
}
示例#3
0
static void do_write_tests(confdb_handle_t handle)
{
	int res;
	unsigned int incdec_value;
	hdb_handle_t object_handle;
	char error_string[1024];

	/* Add a scratch object and put some keys into it */
	res = confdb_object_create(handle, OBJECT_PARENT_HANDLE, "testconfdb", strlen("testconfdb"), &object_handle);
	if (res != CS_OK) {
		printf( "error creating 'testconfdb' object: %d\n", res);
		return;
	}

	res = confdb_key_create(handle, object_handle, "testkey", strlen("testkey"), "one", strlen("one"));
	if (res != CS_OK) {
		printf( "error creating 'testconfdb' key 1: %d\n", res);
		return;
	}

	res = confdb_key_create(handle, object_handle, "testkey", strlen("testkey"), "two", strlen("two"));
	if (res != CS_OK) {
		printf( "error creating 'testconfdb' key 2: %d\n", res);
		return;
	}

	res = confdb_key_create(handle, object_handle, "grot", strlen("grot"), "perrins", strlen("perrins"));
	if (res != CS_OK) {
		printf( "error creating 'testconfdb' key 3: %d\n", res);
		return;
	}

	res = confdb_key_replace(handle, object_handle, "testkey", strlen("testkey"), "two", strlen("two"),
				 "newtwo", strlen("newtwo"));

	if (res != CS_OK) {
		printf( "error replace 'testconfdb' key 2: %d\n", res);
		return;
	}

	/* Print it for verification */
	print_config_tree(handle, object_handle, 0);

	incdec_value = INCDEC_VALUE;
	res = confdb_key_create(handle, object_handle, "incdec", strlen("incdec"), &incdec_value, sizeof(incdec_value));
	if (res != CS_OK) {
		printf( "error creating 'testconfdb' key 4: %d\n", res);
		return;
	}
	res = confdb_key_increment(handle, object_handle, "incdec", strlen("incdec"), &incdec_value);
	if (res != CS_OK) {
		printf( "error incrementing 'testconfdb' key 4: %d\n", res);
		return;
	}
	if (incdec_value == INCDEC_VALUE+1)
		printf("incremented value = %d\n", incdec_value);
	else
		printf("ERROR: incremented value = %d (should be %d)\n", incdec_value, INCDEC_VALUE+1);

	res = confdb_key_decrement(handle, object_handle, "incdec", strlen("incdec"), &incdec_value);
	if (res != CS_OK) {
		printf( "error decrementing 'testconfdb' key 4: %d\n", res);
		return;
	}
	if (incdec_value == INCDEC_VALUE)
		printf("decremented value = %d\n", incdec_value);
	else
		printf("ERROR: decremented value = %d (should be %d)\n", incdec_value, INCDEC_VALUE);

	printf("-------------------------\n");

	/* Remove it.
	   Check that it doesn't exist when the full tree dump runs next */
	res = confdb_object_destroy(handle, object_handle);
	if (res != CS_OK) {
		printf( "error destroying 'testconfdb' object: %d\n", res);
		return;
	}

	res = confdb_write(handle, error_string, sizeof error_string);
	printf("confdb_write returned %d: %s\n", res, error_string);
}
示例#4
0
static void create_object_key(confdb_handle_t handle, char *name_pt)
{
	char * obj_name_pt;
	char * new_obj_name_pt;
	char * save_pt;
	hdb_handle_t obj_handle;
	hdb_handle_t parent_object_handle = OBJECT_PARENT_HANDLE;
	char tmp_name[OBJ_NAME_SIZE];
	cs_error_t res;
	char parent_name[OBJ_NAME_SIZE];
	char key_name[OBJ_NAME_SIZE];
	char key_value[OBJ_NAME_SIZE];

	get_parent_name(name_pt, parent_name);
	get_key(name_pt, key_name, key_value);

	strncpy (tmp_name, parent_name, sizeof (tmp_name));
	tmp_name[sizeof (tmp_name) - 1] = '\0';
	obj_name_pt = strtok_r(tmp_name, SEPERATOR_STR, &save_pt);

	/*
	 * Create parent object tree
	 */
	while (obj_name_pt != NULL) {
		res = confdb_object_find_start(handle, parent_object_handle);
		if (res != CS_OK) {
			fprintf (stderr, "Could not start object_find %d\n", res);
			exit (EXIT_FAILURE);
		}

		new_obj_name_pt = strtok_r (NULL, SEPERATOR_STR, &save_pt);
		res = confdb_object_find(handle, parent_object_handle,
			 obj_name_pt, strlen (obj_name_pt), &obj_handle);
		if (res != CS_OK || new_obj_name_pt == NULL) {

			if (validate_name(obj_name_pt) != CS_OK) {
				fprintf(stderr, "Incorrect object name \"%s\", \"=\" not allowed.\n",
						obj_name_pt);
				exit(EXIT_FAILURE);
			}

			if (debug)
				printf ("%s:%d: %s\n", __func__,__LINE__, obj_name_pt);
			res = confdb_object_create (handle,
				parent_object_handle,
				obj_name_pt,
				strlen (obj_name_pt),
				&obj_handle);
			if (res != CS_OK) {
				fprintf(stderr, "Failed to create object \"%s\". Error %d.\n",
					obj_name_pt, res);
			}
		}
		parent_object_handle = obj_handle;
		obj_name_pt = new_obj_name_pt;
	}

	/*
	 * Create key
	 */
	res = confdb_key_create_typed (handle,
		obj_handle,
		key_name,
		key_value,
		strlen(key_value),
		CONFDB_VALUETYPE_STRING);
	if (res != CS_OK) {
		fprintf(stderr,
			"Failed to create the key %s=%s. Error %d\n",
			key_name, key_value, res);
	}
}
示例#5
0
文件: sam.c 项目: emrehe/corosync
static cs_error_t sam_confdb_register (void)
{
	const char *obj_name;
	cs_error_t err;
	confdb_handle_t confdb_handle;
	hdb_handle_t resource_handle, process_handle, pid_handle, obj_handle;
	hdb_handle_t *res_handle;
	char tmp_obj[PATH_MAX];
	int i;

	if ((err = confdb_initialize (&confdb_handle, NULL)) != CS_OK) {
		return (err);
	}

	for (i = 0; i < 3; i++) {
		switch (i) {
		case 0:
			obj_name = "resources";
			obj_handle = OBJECT_PARENT_HANDLE;
			res_handle = &resource_handle;
			break;
		case 1:
			obj_name = "process";
			obj_handle = resource_handle;
			res_handle = &process_handle;
			break;
		case 2:
			if (snprintf (tmp_obj, sizeof (tmp_obj), "%s:%d", __progname, getpid ()) >= sizeof (tmp_obj)) {
				snprintf (tmp_obj, sizeof (tmp_obj), "%d", getpid ());
			}

			obj_name = tmp_obj;
			obj_handle = process_handle;
			res_handle = &pid_handle;
			break;
		}

		if ((err = confdb_object_find_start (confdb_handle, obj_handle)) != CS_OK) {
			goto finalize_error;
		}

		if ((err = confdb_object_find (confdb_handle, obj_handle, obj_name, strlen (obj_name),
			res_handle)) != CS_OK) {
			if (err == CONFDB_ERR_ACCESS) {
				/*
				 * Try to create object
				 */
				if ((err = confdb_object_create (confdb_handle, obj_handle, obj_name,
					strlen (obj_name), res_handle)) != CS_OK) {
					goto finalize_error;
				}
			} else {
				goto finalize_error;
			}
		} else  {
			if ((err = confdb_object_find_destroy (confdb_handle, obj_handle)) != CS_OK) {
				goto finalize_error;
			}
		}
	}

	sam_internal_data.confdb_pid_handle = pid_handle;
	sam_internal_data.confdb_handle = confdb_handle;

	if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_RECOVERY, NULL)) != CS_OK) {
		goto destroy_finalize_error;
	}

	if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_HC_PERIOD, NULL)) != CS_OK) {
		goto destroy_finalize_error;
	}

	return (CS_OK);

destroy_finalize_error:
	sam_confdb_destroy_pid_obj ();
finalize_error:
	confdb_finalize (confdb_handle);
	return (err);
}
示例#6
0
int
main(int argc, char *argv[])
{
#ifdef USE_CONFDB
	confdb_handle_t handle;
	confdb_callbacks_t callbacks;
	hdb_handle_t object_handle;
#endif
#ifdef USE_CMAP
	cmap_handle_t handle;
	cmap_track_handle_t track_handle;
	int retries;
	cs_error_t result;
#endif
	uint32_t u32;
	int status;
	int i;
	cs_error_t res;
	char str_val[255];
	int ch;
	char *ep;

	change_uint32 = 0;
	change_str_len = 0;
	no_childs = 16;
	burst_count = 64;

	while ((ch = getopt(argc, argv, "hus:c:n:")) != -1) {
		switch (ch) {
		case 'u':
			change_uint32 = 1;
			break;
		case 's':
			change_str_len = strtol(optarg, &ep, 10);
			if (change_str_len <= 0 || *ep != '\0') {
				warnx("illegal number, -s argument -- %s", optarg);
				usage();
			}
			break;
		case 'c':
			no_childs = strtol(optarg, &ep, 10);
			if (no_childs <= 0 || *ep != '\0') {
				warnx("illegal number, -c argument -- %s", optarg);
				usage();
			}
			break;
		case 'n':
			burst_count = strtol(optarg, &ep, 10);
			if (burst_count <= 0 || *ep != '\0') {
				warnx("illegal number, -n argument -- %s", optarg);
				usage();
			}
			break;
		case 'h':
		case '?':
		default:
			usage();
			/* NOTREACHED */
		}
	}

	signal(SIGPIPE, SIG_IGN);

	setlinebuf(stdout);

#ifdef USE_CONFDB
	memset(&callbacks, 0, sizeof(callbacks));
	assert(confdb_initialize(&handle, &callbacks) == CS_OK);
	assert(confdb_object_create(handle, OBJECT_PARENT_HANDLE,
		"testconfdb", strlen("testconfdb"), &object_handle) == CS_OK);
	assert(confdb_finalize(handle) == CS_OK);
#endif

	my_id = create_childs();
	u32 = my_id;

#ifdef USE_CONFDB
	snprintf(my_key_uint, sizeof(my_key_uint), "testkeyu32id%u", my_id);

	snprintf(my_key_str, sizeof(my_key_str), "testkeystrid%u", my_id);
#endif

#ifdef USE_CMAP
	snprintf(my_key_uint, sizeof(my_key_uint), "testconfdb.testkeyu32id%u", my_id);

	snprintf(my_key_str, sizeof(my_key_str), "testconfdb.testkeystrid%u", my_id);
#endif

	for (i = 0; i < change_str_len; i++) {
		str_val[i] = ((my_id + i) % ('Z' - 'A' + 1)) + 'A';
	}
	str_val[i] = '\0';

	if (my_id > 0) {
#ifdef USE_CONFDB
		memset(&callbacks, 0, sizeof(callbacks));
		callbacks.confdb_key_change_notify_fn = confdb_key_change_notify;

		assert(confdb_initialize(&handle, &callbacks) == CS_OK);
#endif

#ifdef USE_CMAP
		retries = 0;
		cs_repeat(retries, 30, result = cmap_initialize(&handle));
		assert(result == CS_OK);
#endif
		if (change_uint32) {
#ifdef USE_CONFDB
			assert(confdb_key_create_typed(handle, object_handle, my_key_uint,
				&u32, sizeof(u32), CONFDB_VALUETYPE_UINT32) == CS_OK);
#endif
#ifdef USE_CMAP
			assert(cmap_set_uint32(handle, my_key_uint, u32) == CS_OK);
#endif
		}

		if (change_str_len > 0) {
#ifdef USE_CONFDB
			assert(confdb_key_create_typed(handle, object_handle, my_key_str,
				str_val, strlen(str_val), CONFDB_VALUETYPE_STRING) == CS_OK);
#endif
#ifdef USE_CMAP
			assert(cmap_set_string(handle, my_key_str, str_val) == CS_OK);
#endif
		}
	} else {
		/*
		 * "Wait" for other processes to initialize
		 */
		poll(NULL, 0, 1000);

		printf("Confdb-track-and-change initialization finished\n");
	}

	if (my_id > 0) {
		signal(SIGINT, sigint_handler_child);

#ifdef USE_CONFDB
		assert(confdb_track_changes(handle, object_handle, OBJECT_KEY_REPLACED) == CS_OK);
#endif

#ifdef USE_CMAP
		assert(cmap_track_add(handle, "testconfdb.", CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
			cmap_notify, NULL, &track_handle) == CS_OK);
#endif

		if (change_uint32) {
#ifdef USE_CONFDB
			assert(confdb_key_increment(handle, object_handle, my_key_uint,
						strlen(my_key_uint), &u32) == CS_OK);
#endif
#ifdef USE_CMAP
			assert(cmap_inc(handle, my_key_uint) == CS_OK);
#endif
			expected_msgs_uint = 1;
		}

		if (change_str_len > 0) {
			inc_str(str_val, change_str_len);
#ifdef USE_CONFDB
			assert(confdb_key_replace(handle, object_handle, my_key_str, strlen(my_key_str), NULL, 0,
					str_val, strlen(str_val)) == CS_OK);
#endif
#ifdef USE_CMAP
			assert(cmap_set_string(handle, my_key_str, str_val) == CS_OK);
#endif
			expected_msgs_str = 1;
		}

		/*
		 * Give other processes a little time to initialize
		 */
		poll(NULL, 0, 250);

		do {
#ifdef USE_CONFDB
			res = confdb_dispatch(handle, CS_DISPATCH_BLOCKING);
#endif
#ifdef USE_CMAP
			res = cmap_dispatch(handle, CS_DISPATCH_BLOCKING);
#endif
		} while (res == CS_OK || res == CS_ERR_TRY_AGAIN);
	} else {
		signal(SIGINT, sigint_handler_parent);

		for (i = 0; i < no_childs; i++) {
			wait(&status);
		}

#ifdef USE_CONFDB
		confdb_object_destroy(handle, object_handle);
#endif
		printf("Confdb-track-and-change finalization finished\n");
	}

	return (0);
}