|
Packit |
366192 |
/* Author: Joshua Brindle
|
|
Packit |
366192 |
* Jason Tang <jtang@tresys.com>
|
|
Packit |
366192 |
*
|
|
Packit |
366192 |
* Copyright (C) 2004-2005 Tresys Technology, LLC
|
|
Packit |
366192 |
* Copyright (C) 2005 Red Hat, Inc.
|
|
Packit |
366192 |
*
|
|
Packit |
366192 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
366192 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
366192 |
* License as published by the Free Software Foundation; either
|
|
Packit |
366192 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
366192 |
*
|
|
Packit |
366192 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
366192 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
366192 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
366192 |
* Lesser General Public License for more details.
|
|
Packit |
366192 |
*
|
|
Packit |
366192 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
366192 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
366192 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
366192 |
*/
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* This file implements only the publicly-visible handle functions to libsemanage. */
|
|
Packit |
366192 |
|
|
Packit |
366192 |
#include <selinux/selinux.h>
|
|
Packit |
366192 |
|
|
Packit |
366192 |
#include <ctype.h>
|
|
Packit |
366192 |
#include <stdarg.h>
|
|
Packit |
366192 |
#include <assert.h>
|
|
Packit |
366192 |
#include <stdlib.h>
|
|
Packit |
366192 |
#include <stdio.h>
|
|
Packit |
366192 |
#include <string.h>
|
|
Packit |
366192 |
#include <sys/time.h>
|
|
Packit |
366192 |
|
|
Packit |
366192 |
#include "direct_api.h"
|
|
Packit |
366192 |
#include "handle.h"
|
|
Packit |
366192 |
#include "debug.h"
|
|
Packit |
366192 |
#include "semanage_conf.h"
|
|
Packit |
366192 |
#include "semanage_store.h"
|
|
Packit |
366192 |
|
|
Packit |
366192 |
#define SEMANAGE_COMMIT_READ_WAIT 5
|
|
Packit |
366192 |
|
|
Packit |
366192 |
static char *private_semanage_root = NULL;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_set_root(const char *root)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
free(private_semanage_root);
|
|
Packit |
366192 |
private_semanage_root = strdup(root);
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden_def(semanage_set_root);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
const char * semanage_root(void)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
if (private_semanage_root == NULL) {
|
|
Packit |
366192 |
return "";
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
return private_semanage_root;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden_def(semanage_root);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
semanage_handle_t *semanage_handle_create(void)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
semanage_handle_t *sh = NULL;
|
|
Packit |
366192 |
char *conf_name = NULL;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Allocate handle */
|
|
Packit |
366192 |
if ((sh = calloc(1, sizeof(semanage_handle_t))) == NULL)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if ((conf_name = semanage_conf_path()) == NULL)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if ((sh->conf = semanage_conf_parse(conf_name)) == NULL)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Link to sepol handle */
|
|
Packit |
366192 |
sh->sepolh = sepol_handle_create();
|
|
Packit |
366192 |
if (!sh->sepolh)
|
|
Packit |
366192 |
goto err;
|
|
Packit |
366192 |
sepol_msg_set_callback(sh->sepolh, semanage_msg_relay_handler, sh);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Default priority is 400 */
|
|
Packit |
366192 |
sh->priority = 400;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* By default do not rebuild the policy on commit
|
|
Packit |
366192 |
* If any changes are made, this flag is ignored */
|
|
Packit |
366192 |
sh->do_rebuild = 0;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->commit_err = 0;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* By default always reload policy after commit if SELinux is enabled. */
|
|
Packit |
366192 |
sh->do_reload = (is_selinux_enabled() > 0);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* By default always check the file contexts file. */
|
|
Packit |
366192 |
sh->do_check_contexts = 1;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* By default do not create store */
|
|
Packit |
366192 |
sh->create_store = 0;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Set timeout: some default value for now, later use config */
|
|
Packit |
366192 |
sh->timeout = SEMANAGE_COMMIT_READ_WAIT;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Set callback */
|
|
Packit |
366192 |
sh->msg_callback = semanage_msg_default_handler;
|
|
Packit |
366192 |
sh->msg_callback_arg = NULL;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
free(conf_name);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return sh;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
err:
|
|
Packit |
366192 |
free(conf_name);
|
|
Packit |
366192 |
semanage_handle_destroy(sh);
|
|
Packit |
366192 |
return NULL;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_rebuild(semanage_handle_t * sh, int do_rebuild)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->do_rebuild = do_rebuild;
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_reload(semanage_handle_t * sh, int do_reload)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->do_reload = do_reload;
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_get_hll_compiler_path(semanage_handle_t *sh,
|
|
Packit |
366192 |
char *lang_ext,
|
|
Packit |
366192 |
char **compiler_path)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
assert(lang_ext != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int i;
|
|
Packit |
366192 |
int status = 0;
|
|
Packit |
366192 |
int num_printed = 0;
|
|
Packit |
366192 |
size_t len;
|
|
Packit |
366192 |
char *compiler = NULL;
|
|
Packit |
366192 |
char *lower_lang_ext = NULL;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
lower_lang_ext = strdup(lang_ext);
|
|
Packit |
366192 |
if (lower_lang_ext == NULL) {
|
|
Packit |
366192 |
ERR(sh, "Could not create copy of lang_ext. Out of memory.\n");
|
|
Packit |
366192 |
status = -1;
|
|
Packit |
366192 |
goto cleanup;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
/* Set lang_ext to lowercase in case a file with a mixed case extension was passed to libsemanage */
|
|
Packit |
366192 |
for (i = 0; lower_lang_ext[i] != '\0'; i++) {
|
|
Packit |
366192 |
lower_lang_ext[i] = tolower(lower_lang_ext[i]);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
len = strlen(sh->conf->compiler_directory_path) + strlen("/") + strlen(lower_lang_ext) + 1;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
compiler = malloc(len * sizeof(*compiler));
|
|
Packit |
366192 |
if (compiler == NULL) {
|
|
Packit |
366192 |
ERR(sh, "Error allocating space for compiler path.");
|
|
Packit |
366192 |
status = -1;
|
|
Packit |
366192 |
goto cleanup;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
num_printed = snprintf(compiler, len, "%s/%s", sh->conf->compiler_directory_path, lower_lang_ext);
|
|
Packit |
366192 |
if (num_printed < 0 || (int)num_printed >= (int)len) {
|
|
Packit |
366192 |
ERR(sh, "Error creating compiler path.");
|
|
Packit |
366192 |
status = -1;
|
|
Packit |
366192 |
goto cleanup;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
*compiler_path = compiler;
|
|
Packit |
366192 |
status = 0;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
cleanup:
|
|
Packit |
366192 |
free(lower_lang_ext);
|
|
Packit |
366192 |
if (status != 0) {
|
|
Packit |
366192 |
free(compiler);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return status;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_create_store(semanage_handle_t * sh, int create_store)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->create_store = create_store;
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_get_disable_dontaudit(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return sepol_get_disable_dontaudit(sh->sepolh);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_disable_dontaudit(semanage_handle_t * sh, int disable_dontaudit)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sepol_set_disable_dontaudit(sh->sepolh, disable_dontaudit);
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_get_preserve_tunables(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
return sepol_get_preserve_tunables(sh->sepolh);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_preserve_tunables(semanage_handle_t * sh,
|
|
Packit |
366192 |
int preserve_tunables)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
sepol_set_preserve_tunables(sh->sepolh, preserve_tunables);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_get_ignore_module_cache(semanage_handle_t *sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
return sh->conf->ignore_module_cache;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_ignore_module_cache(semanage_handle_t *sh,
|
|
Packit |
366192 |
int ignore_module_cache)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
sh->conf->ignore_module_cache = ignore_module_cache;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_check_contexts(semanage_handle_t * sh, int do_check_contexts)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->do_check_contexts = do_check_contexts;
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
uint16_t semanage_get_default_priority(semanage_handle_t *sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
return sh->priority;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_set_default_priority(semanage_handle_t *sh, uint16_t priority)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* Verify priority */
|
|
Packit |
366192 |
if (semanage_module_validate_priority(priority) < 0) {
|
|
Packit |
366192 |
ERR(sh, "Priority %d is invalid.", priority);
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
sh->priority = priority;
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_is_connected(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
return sh->is_connected;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_select_store(semanage_handle_t * sh, char *storename,
|
|
Packit |
366192 |
enum semanage_connect_type storetype)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/* This just sets the storename to what the user requests, no
|
|
Packit |
366192 |
verification of existance will be done until connect */
|
|
Packit |
366192 |
free(sh->conf->store_path);
|
|
Packit |
366192 |
sh->conf->store_path = strdup(storename);
|
|
Packit |
366192 |
assert(sh->conf->store_path); /* no way to return failure */
|
|
Packit |
366192 |
sh->conf->store_type = storetype;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_set_store_root(semanage_handle_t *sh, const char *store_root)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
|
|
Packit |
366192 |
free(sh->conf->store_root_path);
|
|
Packit |
366192 |
sh->conf->store_root_path = strdup(store_root);
|
|
Packit |
366192 |
assert(sh->conf->store_root_path); /* no way to return failure */
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_is_managed(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
if (sh->is_connected) {
|
|
Packit |
366192 |
ERR(sh, "Already connected.");
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
switch (sh->conf->store_type) {
|
|
Packit |
366192 |
case SEMANAGE_CON_DIRECT:
|
|
Packit |
366192 |
return semanage_direct_is_managed(sh);
|
|
Packit |
366192 |
default:
|
|
Packit |
366192 |
ERR(sh,
|
|
Packit |
366192 |
"The connection type specified within your semanage.conf file has not been implemented yet.");
|
|
Packit |
366192 |
/* fall through */
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_mls_enabled(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
switch (sh->conf->store_type) {
|
|
Packit |
366192 |
case SEMANAGE_CON_DIRECT:
|
|
Packit |
366192 |
return semanage_direct_mls_enabled(sh);
|
|
Packit |
366192 |
default:
|
|
Packit |
366192 |
ERR(sh,
|
|
Packit |
366192 |
"The connection type specified within your semanage.conf file has not been implemented yet.");
|
|
Packit |
366192 |
/* fall through */
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_connect(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
switch (sh->conf->store_type) {
|
|
Packit |
366192 |
case SEMANAGE_CON_DIRECT:{
|
|
Packit |
366192 |
if (semanage_direct_connect(sh) < 0) {
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
break;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
default:{
|
|
Packit |
366192 |
ERR(sh,
|
|
Packit |
366192 |
"The connection type specified within your semanage.conf file has not been implemented yet.");
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
sh->is_connected = 1;
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_access_check(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL);
|
|
Packit |
366192 |
switch (sh->conf->store_type) {
|
|
Packit |
366192 |
case SEMANAGE_CON_DIRECT:
|
|
Packit |
366192 |
return semanage_direct_access_check(sh);
|
|
Packit |
366192 |
default:
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
return -1; /* unreachable */
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden_def(semanage_access_check)
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_disconnect(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL && sh->funcs != NULL
|
|
Packit |
366192 |
&& sh->funcs->disconnect != NULL);
|
|
Packit |
366192 |
if (!sh->is_connected) {
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
if (sh->funcs->disconnect(sh) < 0) {
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
sh->is_in_transaction = 0;
|
|
Packit |
366192 |
sh->is_connected = 0;
|
|
Packit |
366192 |
sh->modules_modified = 0;
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
void semanage_handle_destroy(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
if (sh == NULL)
|
|
Packit |
366192 |
return;
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (sh->funcs != NULL && sh->funcs->destroy != NULL)
|
|
Packit |
366192 |
sh->funcs->destroy(sh);
|
|
Packit |
366192 |
semanage_conf_destroy(sh->conf);
|
|
Packit |
366192 |
sepol_handle_destroy(sh->sepolh);
|
|
Packit |
366192 |
free(sh);
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden_def(semanage_handle_destroy)
|
|
Packit |
366192 |
|
|
Packit |
366192 |
/********************* public transaction functions *********************/
|
|
Packit |
366192 |
int semanage_begin_transaction(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
assert(sh != NULL && sh->funcs != NULL
|
|
Packit |
366192 |
&& sh->funcs->begin_trans != NULL);
|
|
Packit |
366192 |
if (!sh->is_connected) {
|
|
Packit |
366192 |
ERR(sh, "Not connected.");
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
if (sh->is_in_transaction) {
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
if (sh->funcs->begin_trans(sh) < 0) {
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
sh->is_in_transaction = 1;
|
|
Packit |
366192 |
return 0;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
|
|
Packit |
366192 |
hidden_def(semanage_begin_transaction)
|
|
Packit |
366192 |
|
|
Packit |
366192 |
int semanage_commit(semanage_handle_t * sh)
|
|
Packit |
366192 |
{
|
|
Packit |
366192 |
int retval;
|
|
Packit |
366192 |
assert(sh != NULL && sh->funcs != NULL && sh->funcs->commit != NULL);
|
|
Packit |
366192 |
if (!sh->is_in_transaction) {
|
|
Packit |
366192 |
ERR(sh,
|
|
Packit |
366192 |
"Will not commit because caller does not have a transaction lock yet.");
|
|
Packit |
366192 |
return -1;
|
|
Packit |
366192 |
}
|
|
Packit |
366192 |
retval = sh->funcs->commit(sh);
|
|
Packit |
366192 |
sh->is_in_transaction = 0;
|
|
Packit |
366192 |
sh->modules_modified = 0;
|
|
Packit |
366192 |
return retval;
|
|
Packit |
366192 |
}
|