예제 #1
0
int ncds_custom_lock(struct ncds_ds* ds, const struct nc_session* session, NC_DATASTORE target, struct nc_err** error) {
	int retval, localinfo = 0;
	const char *sid = NULL;
	struct ncds_ds_custom *c_ds = (struct ncds_ds_custom *) ds;
	struct ncds_lockinfo *linfo;
	pthread_mutex_t* linfo_mut = NULL;

	linfo = get_lockinfo(target, &linfo_mut);
	if (linfo == NULL) {
		*error = nc_err_new(NC_ERR_BAD_ELEM);
		nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "target");
		return (EXIT_FAILURE);
	}

	pthread_mutex_lock(linfo_mut);
	if (c_ds->callbacks->is_locked == NULL) {
		/* is_locked() is not implemented by custom datastore, use local info */
		localinfo = 1;
		if (linfo->sid != NULL) {
			/* datastore is already locked */
			retval = 1;
			sid = linfo->sid;
		} else {
			retval = 0;
		}
	} else {
		/* take locking access into custom datastore plugin */
		sem_wait(cds_lock); /* localinfo = 0 */

		/* get current info using is_locked() */
		retval = c_ds->callbacks->is_locked(c_ds->data, target, &sid, NULL);
		if (retval < 0) { /* error */
			sem_post(cds_lock);
			pthread_mutex_unlock(linfo_mut);
			ERROR("%s: custom datastore's is_locked() function failed (error %d)", __func__, retval);
			*error = nc_err_new(NC_ERR_OP_FAILED);
			nc_err_set(*error, NC_ERR_PARAM_MSG, "custom datastore's is_locked() function failed");
			return (EXIT_FAILURE);
		}
	}

	/* check current status of the lock */
	if (retval == 0 || localinfo) {
		/* datastore is not locked (or we are not sure), try to lock it */
		retval = c_ds->callbacks->lock(c_ds->data, target, session->session_id, error);
	} else { /* retval == 1 && localinfo == 0 */
		/* datastore is already locked */
		*error = nc_err_new(NC_ERR_LOCK_DENIED);
		nc_err_set(*error, NC_ERR_PARAM_INFO_SID, sid);
		retval = EXIT_FAILURE;
	}

	/* drop locking access into custom datastore plugin */
	if (localinfo == 0) {
		sem_post(cds_lock);
	}

	/* update localinfo structure */
	if (retval == EXIT_SUCCESS) {
		linfo->time = nc_time2datetime(time(NULL), NULL);
		linfo->sid = strdup(session->session_id);
	}

	pthread_mutex_unlock(linfo_mut);
	return (retval);
}
예제 #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);
}