void Session::lock_module(const char *module_name) { int ret = sr_lock_module(_sess, module_name); if (ret != SR_ERR_OK) { throw_exception(ret); } }
/** * @brief Performs the program's main operation: lets user to edit specified module and datastore * using the preferred editor. New configuration is validated before it is saved. */ static int srcfg_edit_operation(const char *module_name, srcfg_datastore_t datastore, LYD_FORMAT format, const char *editor, bool keep, bool permanent) { int rc = SR_ERR_INTERNAL, ret = 0; struct ly_ctx *ly_ctx = NULL; char tmpfile_path[PATH_MAX] = { 0, }, cmd[2*PATH_MAX+4] = { 0, }; char *dest = NULL; int fd_tmp = -1; bool locked = false; pid_t child_pid = -1; int child_status = 0, first_attempt = 1; CHECK_NULL_ARG2(module_name, editor); /* init libyang context */ ret = srcfg_ly_init(&ly_ctx, module_name); CHECK_RC_MSG_GOTO(ret, fail, "Failed to initialize libyang context."); /* lock module for the time of editing if requested */ if (keep) { rc = sr_lock_module(srcfg_session, module_name); if (SR_ERR_OK != rc) { srcfg_report_error(rc); goto fail; } locked = true; } /* export: */ /* create temporary file for datastore editing */ mode_t orig_umask = umask(S_IRWXO|S_IRWXG); snprintf(tmpfile_path, PATH_MAX, "/tmp/srcfg.%s%s.XXXXXX", module_name, datastore == SRCFG_STORE_RUNNING ? SR_RUNNING_FILE_EXT : SR_STARTUP_FILE_EXT); fd_tmp = mkstemp(tmpfile_path); umask(orig_umask); CHECK_NOT_MINUS1_MSG_GOTO(fd_tmp, rc, SR_ERR_INTERNAL, fail, "Failed to create temporary file for datastore editing."); /* export datastore content into a temporary file */ ret = srcfg_export_datastore(ly_ctx, fd_tmp, module_name, format); if (SR_ERR_OK != ret) { goto fail; } close(fd_tmp); fd_tmp = -1; edit: if (!first_attempt) { if (!srcfg_prompt("Unable to apply the changes. " "Would you like to continue editing the configuration?", "y", "n")) { goto save; } } first_attempt = 0; /* Open the temporary file inside the preferred text editor */ child_pid = fork(); if (0 <= child_pid) { /* fork succeeded */ if (0 == child_pid) { /* child process */ /* Open text editor */ return execlp(editor, editor, tmpfile_path, (char *)NULL); } else { /* parent process */ /* wait for the child to exit */ ret = waitpid(child_pid, &child_status, 0); if (child_pid != ret) { SR_LOG_ERR_MSG("Unable to wait for the editor to exit."); goto save; } /* Check return status from the child */ if (!WIFEXITED(child_status) || 0 != WEXITSTATUS(child_status)) { SR_LOG_ERR_MSG("Text editor didn't start/terminate properly."); goto save; } } } else /* fork failed */ { SR_LOG_ERR_MSG("Failed to fork a new process for the text editor."); goto fail; } /* import: */ /* re-open temporary file */ fd_tmp = open(tmpfile_path, O_RDONLY); CHECK_NOT_MINUS1_MSG_GOTO(fd_tmp, rc, SR_ERR_INTERNAL, save, "Unable to re-open the configuration after it was edited using the text editor."); /* import temporary file content into the datastore */ ret = srcfg_import_datastore(ly_ctx, fd_tmp, module_name, datastore, format, permanent); close(fd_tmp); fd_tmp = -1; if (SR_ERR_OK != ret) { goto edit; } /* operation succeeded */ rc = SR_ERR_OK; printf("The new configuration was successfully applied.\n"); goto cleanup; save: /* save to a (ordinary) file if requested */ if (srcfg_prompt("Failed to commit the new configuration. " "Would you like to save your changes to a file?", "y", "n")) { /* copy whatever is in the temporary file right now */ snprintf(cmd, PATH_MAX + 4, "cp %s ", tmpfile_path); dest = cmd + strlen(cmd); do { printf("Enter a file path: "); ret = scanf("%" PATH_MAX_STR "s", dest); if (EOF == ret) { SR_LOG_ERR_MSG("Scanf failed: end of the input stream."); goto discard; } sr_str_trim(dest); ret = system(cmd); if (0 != ret) { printf("Unable to save the configuration to '%s'. ", dest); if (!srcfg_prompt("Retry?", "y", "n")) { goto discard; } } } while (0 != ret); printf("Your changes have been saved to '%s'. " "You may try to apply them again using the import operation.\n", dest); goto cleanup; } discard: printf("Your changes were discarded.\n"); goto cleanup; fail: printf("Errors were encountered during editing. Cancelling the operation.\n"); cleanup: if (-1 != fd_tmp) { close(fd_tmp); } if ('\0' != tmpfile_path[0]) { unlink(tmpfile_path); } if (locked) { rc = sr_unlock_module(srcfg_session, module_name); if (SR_ERR_OK != rc) { srcfg_report_error(rc); } } if (ly_ctx) { ly_ctx_destroy(ly_ctx, NULL); } return rc; }