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); }
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); }