Ejemplo n.º 1
0
int module_enable(struct np_module* module, int add) {
	char *config_path = NULL, *repo_path = NULL, *repo_type_str = NULL;
	int repo_type = -1, main_model_count;
	xmlDocPtr module_config;
	xmlNodePtr node;
	xmlXPathContextPtr xpath_ctxt;
	xmlXPathObjectPtr xpath_obj;

	if (asprintf(&config_path, "%s/%s.xml", MODULES_CFG_DIR, module->name) == -1) {
		nc_verb_error("asprintf() failed (%s:%d).", __FILE__, __LINE__);
		return(EXIT_FAILURE);
	}
	if ((module_config = xmlReadFile(config_path, NULL, XML_PARSE_NOBLANKS|XML_PARSE_NSCLEAN|XML_PARSE_NOWARNING|XML_PARSE_NOERROR)) == NULL) {
		nc_verb_error("Reading configuration for %s module failed", module->name);
		free(config_path);
		return(EXIT_FAILURE);
	}
	free(config_path);

	if ((xpath_ctxt = xmlXPathNewContext(module_config)) == NULL) {
		nc_verb_error("Creating XPath context failed (%s:%d - module %s)", __FILE__, __LINE__, module->name);
		return (EXIT_FAILURE);
	}

	/* get datastore information */
	if ((xpath_obj = xmlXPathEvalExpression(BAD_CAST "/device/repo", xpath_ctxt)) == NULL) {
		nc_verb_error("XPath evaluating error (%s:%d)", __FILE__, __LINE__);
		goto err_cleanup;
	} else if (xpath_obj->nodesetval == NULL || xpath_obj->nodesetval->nodeNr != 1) {
		nc_verb_verbose("repo is not unique in %s transAPI module configuration.", module->name);
		xmlXPathFreeObject(xpath_obj);
		goto err_cleanup;
	}

	for (node = xpath_obj->nodesetval->nodeTab[0]->children; node != NULL; node = node->next) {
		if (node->type != XML_ELEMENT_NODE) {
			continue;
		}
		if (xmlStrcmp(node->name, BAD_CAST "type") == 0) {
			repo_type_str = (char*)xmlNodeGetContent(node);
		} else if (xmlStrcmp(node->name, BAD_CAST "path") == 0) {
			repo_path = (char*)xmlNodeGetContent(node);
		}
	}
	if (repo_type_str == NULL) {
		nc_verb_warning("Missing attribute \'type\' in repo element for %s transAPI module.", module->name);
		repo_type_str = strdup("unknown");
	}
	if (strcmp(repo_type_str, "empty") == 0) {
		repo_type = NCDS_TYPE_EMPTY;
	} else if (strcmp(repo_type_str, "file") == 0) {
		repo_type = NCDS_TYPE_FILE;
	} else {
		nc_verb_warning("Unknown repo type \'%s\' in %s transAPI module configuration", repo_type_str, module->name);
		nc_verb_warning("Continuing with \'empty\' datastore type.");
		repo_type = NCDS_TYPE_EMPTY;
	}
	free(repo_type_str);

	if (repo_type == NCDS_TYPE_FILE && repo_path == NULL) {
		nc_verb_error("Missing path for \'file\' datastore type in %s transAPI module configuration.", module->name);
		xmlXPathFreeObject(xpath_obj);
		goto err_cleanup;
	}
	xmlXPathFreeObject(xpath_obj);

	/* get data-models element */
	if ((xpath_obj = xmlXPathEvalExpression(BAD_CAST "/device/data-models", xpath_ctxt)) == NULL) {
		nc_verb_error("XPath evaluating error (%s:%d)", __FILE__, __LINE__);
		goto err_cleanup;
	} else if (xpath_obj->nodesetval == NULL || xpath_obj->nodesetval->nodeNr != 1) {
		nc_verb_verbose("data-models is not unique in %s transAPI module configuration.", module->name);
		xmlXPathFreeObject(xpath_obj);
		goto err_cleanup;
	}

	/* parse models in the config-defined order, both main and augments */
	main_model_count = 0;
	for (node = xpath_obj->nodesetval->nodeTab[0]->children; node != NULL; node = node->next) {
		if (node->type != XML_ELEMENT_NODE) {
			continue;
		}
		if (xmlStrcmp(node->name, BAD_CAST "model") == 0) {
			parse_model_cfg(module, node, -1);
		}
		if (xmlStrcmp(node->name, BAD_CAST "model-main") == 0) {
			parse_model_cfg(module, node, repo_type);
			main_model_count++;
		}
	}
	xmlXPathFreeObject(xpath_obj);
	if (main_model_count == 0) {
		nc_verb_verbose("model-main is not present in %s transAPI module configuration.", module->name);
		goto err_cleanup;
	} else if (main_model_count > 1) {
		nc_verb_verbose("model-main is not unique in %s transAPI module configuration.", module->name);
		goto err_cleanup;
	}

	if (repo_type == NCDS_TYPE_FILE) {
		if (ncds_file_set_path(module->ds, repo_path)) {
			nc_verb_verbose("Unable to set path to datastore of the \'%s\' transAPI module.", module->name);
			goto err_cleanup;
		}
	}
	free(repo_path);
	repo_path = NULL;

	if ((module->id = ncds_init(module->ds)) < 0) {
		goto err_cleanup;
	}

	xmlXPathFreeContext(xpath_ctxt);
	xmlFreeDoc(module_config);

	if (ncds_consolidate() != 0) {
		nc_verb_warning("%s: consolidating libnetconf datastores failed for module %s.", __func__, module->name);
		return (EXIT_FAILURE);
	}

	/* remove datastore locks if any kept */
	if (server_start) {
		ncds_break_locks(NULL);
	}
	if (ncds_device_init(&(module->id), NULL, 1) != 0) {
		nc_verb_error("Device initialization of module %s failed.", module->name);
		ncds_free(module->ds);
		module->ds = NULL;
		return (EXIT_FAILURE);
	}

	if (add) {
		if (netopeer_options.modules) {
			netopeer_options.modules->prev = module;
		}
		module->next = netopeer_options.modules;
		netopeer_options.modules = module;
	}

	return (EXIT_SUCCESS);

err_cleanup:

	xmlXPathFreeContext(xpath_ctxt);
	xmlFreeDoc(module_config);

	ncds_free(module->ds);
	module->ds = NULL;

	free(repo_path);

	return (EXIT_FAILURE);
}
Ejemplo n.º 2
0
API int nc_init(int flags)
{
	int retval = 0, r, init_shm = 1, fd;
	char* t, my_comm[NC_APPS_COMM_MAX+1];
	pthread_rwlockattr_t rwlockattr;
	mode_t mask;
#ifndef POSIX_SHM
	key_t key = -4;
#endif

	if (nc_init_flags & NC_INIT_DONE) {
		ERROR("libnetconf already initiated!");
		return (-1);
	}

#ifndef DISABLE_LIBSSH
	if (flags & NC_INIT_LIBSSH_PTHREAD) {
		ssh_threads_set_callbacks(ssh_threads_get_pthread());
		ssh_init();
		nc_init_flags |= NC_INIT_LIBSSH_PTHREAD;
	}
#endif

	if (flags == NC_INIT_CLIENT) {
		nc_init_flags |= NC_INIT_CLIENT;
		return (retval);
	}

	if ((flags & (NC_INIT_MULTILAYER | NC_INIT_SINGLELAYER)) != NC_INIT_MULTILAYER &&
			(flags & (NC_INIT_MULTILAYER | NC_INIT_SINGLELAYER)) != NC_INIT_SINGLELAYER) {
		ERROR("Either single-layer or multi-layer flag must be used in initialization.");
		return (-1);
	}

	/* some flags need other flags, so check that all dependencies are fullfilled */
	if (flags & NC_INIT_NACM) {
		flags |= NC_INIT_DATASTORES;
	}
	if (flags & NC_INIT_KEEPALIVECHECK) {
		flags |= NC_INIT_MONITORING;
	}

	if (flags & (NC_INIT_DATASTORES | NC_INIT_MONITORING | NC_INIT_NACM)) {
#ifndef POSIX_SHM
		DBG("Shared memory key: %d", key);
		mask = umask(MASK_PERM);
		shmid = shmget(key, sizeof(struct nc_shared_info), IPC_CREAT | IPC_EXCL | FILE_PERM);
		umask(mask);
		if (shmid == -1) {
			if (errno == EEXIST) {
				shmid = shmget(key, sizeof(struct nc_shared_info), 0);
				init_shm = 0;
			}
			if (shmid == -1) {
				ERROR("Accessing System V shared memory failed (%s).", strerror(errno));
				return (-1);
			}
		}
		DBG("Shared memory ID: %d", shmid);

		/* attach memory */
		nc_info = shmat(shmid, NULL, 0);
		if (nc_info == (void*) -1) {
			ERROR("Attaching System V shared memory failed (%s). You can try removing the memory by \"ipcrm -m %d\".", strerror(errno), shmid);
			nc_info = NULL;
			return (-1);
		}

#else

		DBG("Shared memory location: /dev/shm/"NC_POSIX_SHM_OBJECT);
		mask = umask(MASK_PERM);
		fd = shm_open(NC_POSIX_SHM_OBJECT, O_CREAT | O_EXCL | O_RDWR, FILE_PERM);
		umask(mask);
		if (fd == -1) {
			if (errno == EEXIST) {
				DBG("Shared memory file %s already exists - opening", NC_POSIX_SHM_OBJECT);
				fd = shm_open(NC_POSIX_SHM_OBJECT, O_RDWR, 0);
				init_shm = 0;
			}
			if (fd == -1) {
				ERROR("Accessing POSIX shared memory failed (%s).", strerror(errno));
				return (-1);
			}
		}
		DBG("POSIX SHM File Descriptor: %d (%dB).", fd, sizeof(struct nc_shared_info));

		if (ftruncate(fd,sizeof(struct nc_shared_info)) == -1 )  {
			ERROR("Truncating POSIX shared memory failed (%s).", strerror(errno));
			shm_unlink(NC_POSIX_SHM_OBJECT);
			return (-1);
		}

		nc_info = mmap(NULL, sizeof(struct nc_shared_info), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
		if (nc_info == MAP_FAILED) {
			ERROR("Mapping POSIX shared memory failed (%s).", strerror(errno));
			shm_unlink(NC_POSIX_SHM_OBJECT);
			return (-1);
		}

#endif /* #ifndef POSIX_SHM */

		/* get my comm */
		my_comm[0] = '\0';
		fd = open("/proc/self/comm", O_RDONLY);
		if (fd != -1) {
			r = read(fd, my_comm, NC_APPS_COMM_MAX);
			close(fd);
			if (r > 0) {
				if (my_comm[r-1] == '\n') {
					my_comm[r-1] = '\0';
				} else {
					my_comm[r] = '\0';
				}
			}
		}

		if (init_shm) {
			/* we created the shared memory, consider first even for single-layer */
			first_after_close = 1;

			/* clear the apps structure */
			memset(nc_info->apps.valid, 0, NC_APPS_MAX * sizeof(unsigned char));

			/* set last session id */
			nc_info->last_session_id = 0;

			/* init lock */
			pthread_rwlockattr_init(&rwlockattr);
			pthread_rwlockattr_setpshared(&rwlockattr, PTHREAD_PROCESS_SHARED);
			if ((r = pthread_rwlock_init(&(nc_info->lock), &rwlockattr)) != 0) {
				ERROR("Shared information lock initialization failed (%s)", strerror(r));
#ifdef POSIX_SHM
				munmap(nc_info, sizeof(struct nc_shared_info));
				shm_unlink(NC_POSIX_SHM_OBJECT);
#else
				shmdt(nc_info);
#endif /* #ifdef POSIX_SHM */
				return (-1);
			}
			pthread_rwlockattr_destroy(&rwlockattr);

			/* LOCK */
			r = pthread_rwlock_wrlock(&(nc_info->lock));
			memset(nc_info->apps.valid, 0, NC_APPS_MAX * sizeof(unsigned char));
		} else {
			/* LOCK */
			r = pthread_rwlock_wrlock(&(nc_info->lock));

			/* check if I didn't crash before */
			r = nc_apps_check(my_comm, &(nc_info->apps));

			if (r & 1) {
				/* I crashed */
				retval |= NC_INITRET_RECOVERY;
				nc_info->stats.participants--;
			}

			if (r & 2) {
				/* shared memory existed and there are actually some running libnetconf apps */
				first_after_close = 0;
				retval |= NC_INITRET_NOTFIRST;
			} else if (flags & NC_INIT_MULTILAYER) {
				/* shared memory contained only crash info, multi-layer is considered first, ... */
				first_after_close = 1;
			} else {
				/* ... single-layer not */
				first_after_close = 0;
			}
		}

		if (first_after_close) {
			/* we are certain we can do this */
			nc_shared_cleanup(0);

			/* init the information structure */
			strncpy(nc_info->stats.start_time, t = nc_time2datetime(time(NULL), NULL), TIME_LENGTH);
			free(t);
		}

		/* update shared memory with this process's information */
		nc_info->stats.participants++;
		nc_apps_add(my_comm, &(nc_info->apps));

		/* UNLOCK */
		r = pthread_rwlock_unlock(&(nc_info->lock));

	}

	/*
	 * check used flags according to a compile time settings
	 */
	if (flags & NC_INIT_MULTILAYER) {
		nc_init_flags |= NC_INIT_MULTILAYER;
	} else {
		nc_init_flags |= NC_INIT_SINGLELAYER;
	}
#ifndef DISABLE_NOTIFICATIONS
	if (flags & NC_INIT_NOTIF) {
		nc_init_flags |= NC_INIT_NOTIF;
	}
#endif /* DISABLE_NOTIFICATIONS */
	if (flags & NC_INIT_NACM) {
		nc_init_flags |= NC_INIT_NACM;
	}
	if (flags & NC_INIT_MONITORING) {
		nc_init_flags |= NC_INIT_MONITORING;
	}
	if (flags & NC_INIT_DATASTORES) {
		nc_init_flags |= NC_INIT_DATASTORES;
	}
	if (flags & NC_INIT_WD) {
		nc_init_flags |= NC_INIT_WD;
	}
#ifndef DISABLE_VALIDATION
	if (flags & NC_INIT_VALIDATE) {
		nc_init_flags |= NC_INIT_VALIDATE;
	}
#endif
#ifndef DISABLE_URL
	if (flags & NC_INIT_URL) {
		nc_init_flags |= NC_INIT_URL;
	}
#endif
	if (flags & NC_INIT_KEEPALIVECHECK) {
		nc_init_flags |= NC_INIT_KEEPALIVECHECK;
	}

	if (nc_init_flags & NC_INIT_DATASTORES) {
		/*
		 * init internal datastores - they have to be initiated before they are
		 * used by their subsystems initiated below
		 */
		if (ncds_sysinit(nc_init_flags) != EXIT_SUCCESS) {
			nc_init_flags = 0;
			nc_init_flags &= !(NC_INIT_NOTIF & NC_INIT_NACM & NC_INIT_MONITORING & NC_INIT_DATASTORES);
			return (-1);
		}

		if (first_after_close) {
			/* break any locks forgotten from the previous run */
			ncds_break_locks(NULL);

			/* apply startup to running in internal datastores */
			ncds_startup_internal();
		}

		/* set features for ietf-netconf */
		ncds_feature_enable("ietf-netconf", "writable-running");
		ncds_feature_enable("ietf-netconf", "startup");
		ncds_feature_enable("ietf-netconf", "candidate");
		ncds_feature_enable("ietf-netconf", "rollback-on-error");
		if (nc_init_flags & NC_INIT_VALIDATE) {
			ncds_feature_enable("ietf-netconf", "validate");
		}
		if (nc_init_flags & NC_INIT_URL) {
			ncds_feature_enable("ietf-netconf", "url");
		}
	}

	/* init NETCONF sessions statistics */
	if (nc_init_flags & NC_INIT_MONITORING) {
		nc_session_monitoring_init();
	}

	/* init NETCONF with-defaults capability */
	if (nc_init_flags & NC_INIT_WD) {
		ncdflt_set_basic_mode(NCWD_MODE_EXPLICIT);
		ncdflt_set_supported(NCWD_MODE_ALL
		    | NCWD_MODE_ALL_TAGGED
		    | NCWD_MODE_TRIM
		    | NCWD_MODE_EXPLICIT);
	}

#ifndef DISABLE_NOTIFICATIONS
	/* init Notification subsystem */
	if (nc_init_flags & NC_INIT_NOTIF) {
		if (ncntf_init() != EXIT_SUCCESS) {
			/* remove flags of uninitiated subsystems */
			nc_init_flags &= !(NC_INIT_NOTIF & NC_INIT_NACM);

			nc_close();
			return (-1);
		}
	}
#endif

	/* init Access Control subsystem */
	if (nc_init_flags & NC_INIT_NACM) {
		if (nacm_init() != EXIT_SUCCESS) {
			/* remove flags of uninitiated subsystems */
			nc_init_flags &= !NC_INIT_NACM;

			nc_close();
			return (-1);
		}
	}

	nc_init_flags |= NC_INIT_DONE;
	return (retval);
}