Example #1
0
int flom_handle_unlock(flom_handle_t *handle)
{
    enum Exception { NULL_OBJECT
                     , API_INVALID_SEQUENCE
                     , OBJ_CORRUPTED
                     , CLIENT_UNLOCK_ERROR
                     , CLIENT_DISCONNECT_ERROR
                     , NONE } excp;
    int ret_cod = FLOM_RC_INTERNAL_ERROR;
    
    /* check flom library is initialized */
    if (FLOM_RC_OK != (ret_cod = flom_init_check()))
        return ret_cod;
    
    FLOM_TRACE(("flom_handle_unlock\n"));
    TRY {
        struct flom_conn_data_s *cd = NULL;
        /* check handle is not NULL */
        if (NULL == handle)
            THROW(NULL_OBJECT);
        /* cast and retrieve conn_data fron the proxy object */
        cd = (struct flom_conn_data_s *)handle->conn_data;
        /* check handle state */
        if (FLOM_HANDLE_STATE_LOCKED != handle->state &&
            FLOM_HANDLE_STATE_CONNECTED != handle->state) {
            FLOM_TRACE(("flom_handle_unlock: handle->state=%d\n",
                        handle->state));
            THROW(API_INVALID_SEQUENCE);
        }
        /* check the connection data pointer is not NULL (we can't be sure
           it's a valid pointer) */
        if (NULL == handle->conn_data)
            THROW(OBJ_CORRUPTED);
        if (FLOM_HANDLE_STATE_LOCKED == handle->state) {
            /* lock release */
            if (FLOM_RC_OK != (ret_cod = flom_client_unlock(
                                   handle->config, cd)))
                THROW(CLIENT_UNLOCK_ERROR);
            /* state update */
            handle->state = FLOM_HANDLE_STATE_CONNECTED;
        } else {
            FLOM_TRACE(("flom_handle_unlock: resource already unlocked (%d), "
                        "skipping...\n", handle->state));
        }
        /* gracefully disconnect from daemon */
        if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(cd)))
            THROW(CLIENT_DISCONNECT_ERROR);
        /* state update */
        handle->state = FLOM_HANDLE_STATE_DISCONNECTED;
        
        THROW(NONE);
    } CATCH {
        switch (excp) {
            case NULL_OBJECT:
                ret_cod = FLOM_RC_NULL_OBJECT;
                break;
            case API_INVALID_SEQUENCE:
                ret_cod = FLOM_RC_API_INVALID_SEQUENCE;
                break;
            case OBJ_CORRUPTED:
                ret_cod = FLOM_RC_OBJ_CORRUPTED;
                break;
            case CLIENT_UNLOCK_ERROR:
            case CLIENT_DISCONNECT_ERROR:
                break;
            case NONE:
                ret_cod = FLOM_RC_OK;
                break;
            default:
                ret_cod = FLOM_RC_INTERNAL_ERROR;
        } /* switch (excp) */
    } /* TRY-CATCH */
    FLOM_TRACE(("flom_handle_unlock/excp=%d/"
                "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
    return ret_cod;
}
Example #2
0
/**
 * This is a private library function, not exposed in the interface, that's
 * used both by @ref flom_handle_unlock and by
 * @ref flom_handle_unlock_rollback .
 * See above functions for more details.
 * @param handle (Input/Output): a valid object handle
 * @param rollback: a boolean value, TRUE means the state of the transactional
 *        resource must be backed out
 * @return a reason code
 */
int flom_handle_unlock_internal(flom_handle_t *handle, int rollback)
{
    enum Exception { NULL_OBJECT
                     , API_INVALID_SEQUENCE
                     , OBJ_CORRUPTED
                     , CLIENT_UNLOCK_ERROR
                     , CLIENT_DISCONNECT_ERROR
                     , RESOURCE_IS_NOT_TRANSACTIONAL
                     , NONE } excp;
    int ret_cod = FLOM_RC_INTERNAL_ERROR;
    
    /* check flom library is initialized */
    if (FLOM_RC_OK != (ret_cod = flom_init_check()))
        return ret_cod;
    
    FLOM_TRACE(("flom_handle_unlock_internal: rollback=%d\n", rollback));
    TRY {
        flom_conn_t *conn = NULL;
        int ignored_rollback = FALSE;
        
        /* check handle is not NULL */
        if (NULL == handle)
            THROW(NULL_OBJECT);
        /* cast and retrieve conn fron the proxy object */
        conn = (flom_conn_t *)handle->conn;
        /* check handle state */
        if (FLOM_HANDLE_STATE_LOCKED != handle->state &&
            FLOM_HANDLE_STATE_CONNECTED != handle->state) {
            FLOM_TRACE(("flom_handle_unlock_internal: handle->state=%d\n",
                        handle->state));
            THROW(API_INVALID_SEQUENCE);
        }
        /* check the connection data pointer is not NULL (we can't be sure
           it's a valid pointer) */
        if (NULL == handle->conn)
            THROW(OBJ_CORRUPTED);
        /* check transactionality */
        if (rollback) {
            int transactional = flom_rsrc_get_transactional(
                flom_config_get_resource_name(handle->config));
            if (!transactional) {
                FLOM_TRACE(("flom_handle_unlock_internal: asked rollback for "
                            "a non transactional resource ('%s'), "
                            "ignoring...\n",
                            STRORNULL(flom_config_get_resource_name(
                                          handle->config))));
                ignored_rollback = TRUE;
                /* overwrite rollback parameter */
                rollback = FALSE;
            }
        }
        if (FLOM_HANDLE_STATE_LOCKED == handle->state) {
            /* lock release */
            if (FLOM_RC_OK != (ret_cod = flom_client_unlock(
                                   handle->config, conn, rollback)))
                THROW(CLIENT_UNLOCK_ERROR);
            /* state update */
            handle->state = FLOM_HANDLE_STATE_CONNECTED;
        } else {
            FLOM_TRACE(("flom_handle_unlock_internal: resource already "
                        "unlocked (%d), skipping...\n", handle->state));
        }
        /* gracefully disconnect from daemon */
        if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(conn)))
            THROW(CLIENT_DISCONNECT_ERROR);
        /* free locked element name is allocated */
        g_free(handle->locked_element);
        handle->locked_element = NULL;
        /* state update */
        handle->state = FLOM_HANDLE_STATE_DISCONNECTED;

        if (ignored_rollback)
            THROW(RESOURCE_IS_NOT_TRANSACTIONAL);
        
        THROW(NONE);
    } CATCH {
        switch (excp) {
            case NULL_OBJECT:
                ret_cod = FLOM_RC_NULL_OBJECT;
                break;
            case API_INVALID_SEQUENCE:
                ret_cod = FLOM_RC_API_INVALID_SEQUENCE;
                break;
            case OBJ_CORRUPTED:
                ret_cod = FLOM_RC_OBJ_CORRUPTED;
                break;
            case CLIENT_UNLOCK_ERROR:
            case CLIENT_DISCONNECT_ERROR:
                break;
            case NONE:
                ret_cod = FLOM_RC_OK;
                break;
            case RESOURCE_IS_NOT_TRANSACTIONAL:
                ret_cod = FLOM_RC_RESOURCE_IS_NOT_TRANSACTIONAL;
                break;
            default:
                ret_cod = FLOM_RC_INTERNAL_ERROR;
        } /* switch (excp) */
    } /* TRY-CATCH */
    FLOM_TRACE(("flom_handle_unlock_internal/excp=%d/"
                "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
    return ret_cod;
}
Example #3
0
File: main.c Project: 3manuek/flom
int main (int argc, char *argv[])
{
    GError *error = NULL;
    GOptionContext *option_context;
    int child_status = 0;
    int ret_cod = FLOM_RC_INTERNAL_ERROR;
    struct flom_conn_data_s cd;
    char locked_element[100];

    option_context = g_option_context_new("[-- command to execute]");
    g_option_context_add_main_entries(option_context, entries, NULL);
    if (!g_option_context_parse(option_context, &argc, &argv, &error)) {
        g_print("option parsing failed: %s\n", error->message);
        exit(FLOM_ES_GENERIC_ERROR);
    }
    g_option_context_free(option_context);

    if (print_version) {
        g_print("FLoM: Free LOck Manager\n"
                "Copyright (c) 2013-2014, Christian Ferrari; "
                "all rights reserved.\n"
                "License: GPL (GNU Public License) version 2\n"
                "Package name: %s; package version: %s; release date: %s\n"
                "Access http://sourceforge.net/projects/flom/ for "
                "project community activities\n",
                FLOM_PACKAGE_NAME, FLOM_PACKAGE_VERSION, FLOM_PACKAGE_DATE);
        exit(FLOM_ES_OK);
    }

    /* initialize trace destination if necessary */
    FLOM_TRACE_INIT;
    
    /* initialize regular expression table */
    if (FLOM_RC_OK != (ret_cod = global_res_name_preg_init())) {
        g_print("global_res_name_preg_init: ret_cod=%d\n", ret_cod);
        exit(FLOM_ES_GENERIC_ERROR);
    }

    /* reset global configuration */
    flom_config_reset(NULL);
    /* initialize configuration with standard system, standard user and
       user customized config files */
    if (FLOM_RC_OK != (ret_cod = flom_config_init(NULL, config_file))) {
        g_print("flom_config_init: ret_cod=%d\n", ret_cod);
        exit(FLOM_ES_GENERIC_ERROR);
    }
    /* overrides configuration with command line passed arguments */
    if (NULL != daemon_trace_file)
        flom_config_set_daemon_trace_file(NULL, daemon_trace_file);
    if (NULL != command_trace_file)
        flom_config_set_command_trace_file(NULL, command_trace_file);
    if (verbose)
        flom_config_set_verbose(NULL, verbose);
    if (NULL != resource_name)
        if (FLOM_RC_OK != (ret_cod = flom_config_set_resource_name(
                               NULL, resource_name))) {
            g_print("flom_config_set_resource_name: ret_cod=%d\n", ret_cod);
            exit(FLOM_ES_GENERIC_ERROR);
        }
    if (0 > resource_quantity)
        g_warning("Resource quantity ignored because negative values (%d) "
                  "are meaningless\n", resource_quantity);
    else if (0 < resource_quantity)
        flom_config_set_resource_quantity(NULL, resource_quantity);

    if (NULL != resource_wait) {
        flom_bool_value_t fbv;
        if (FLOM_BOOL_INVALID == (
                fbv = flom_bool_value_retrieve(resource_wait))) {
            g_print("resource-wait: '%s' is an invalid value\n",
                    resource_wait);
            exit(FLOM_ES_GENERIC_ERROR);
        }
        flom_config_set_resource_wait(NULL, fbv);
    }
    if (FLOM_NETWORK_WAIT_TIMEOUT != resource_timeout) {
        /* timeout is useless if no wait was specified */
        if (FLOM_BOOL_NO == flom_config_get_resource_wait(NULL))
            g_warning("Timeout ignored because 'no wait' behavior was "
                      "specified\n");
        else
            flom_config_set_resource_timeout(NULL, resource_timeout);
    }
    if (NULL != lock_mode) {
        flom_lock_mode_t flm;
        if (FLOM_LOCK_MODE_INVALID == (
                flm = flom_lock_mode_retrieve(lock_mode))) {
            g_print("lock-mode: '%s' is an invalid value\n", lock_mode);
            exit(FLOM_ES_GENERIC_ERROR);
        }
        flom_config_set_lock_mode(NULL, flm);
    }
    if (NULL != resource_create) {
        flom_bool_value_t fbv;
        if (FLOM_BOOL_INVALID == (
                fbv = flom_bool_value_retrieve(resource_create))) {
            g_print("resource-create: '%s' is an invalid value\n",
                    resource_create);
            exit(FLOM_ES_GENERIC_ERROR);
        }
        flom_config_set_resource_create(NULL, fbv);
    }
    flom_config_set_resource_idle_lifespan(NULL, resource_idle_lifespan);
    if (NULL != socket_name) {
        if (FLOM_RC_OK != (ret_cod = flom_config_set_socket_name(
                               NULL, socket_name))) {
            g_print("socket-name: '%s' is an invalid value\n", socket_name);
            g_print("flom_client_connect: ret_cod=%d (%s)\n",
                    ret_cod, flom_strerror(ret_cod));
            exit(FLOM_ES_GENERIC_ERROR);
        }
    }
    if (_DEFAULT_DAEMON_LIFESPAN != daemon_lifespan) {
        flom_config_set_lifespan(NULL, daemon_lifespan);
    }
    if (NULL != unicast_address) {
        flom_config_set_unicast_address(NULL, unicast_address);
    }
    if (_DEFAULT_DAEMON_PORT != unicast_port) {
        flom_config_set_unicast_port(NULL, unicast_port);
    }
    if (NULL != multicast_address) {
        flom_config_set_multicast_address(NULL, multicast_address);
    }
    if (_DEFAULT_DAEMON_PORT != multicast_port) {
        flom_config_set_multicast_port(NULL, multicast_port);
    }
    if (_DEFAULT_DISCOVERY_ATTEMPTS != discovery_attempts) {
        flom_config_set_discovery_attempts(NULL, discovery_attempts);
    }
    if (_DEFAULT_DISCOVERY_TIMEOUT != discovery_timeout) {
        flom_config_set_discovery_timeout(NULL, discovery_timeout);
    }
    if (_DEFAULT_DISCOVERY_TTL != discovery_ttl) {
        flom_config_set_discovery_ttl(NULL, discovery_ttl);
    }
    if (_DEFAULT_TCP_KEEPALIVE_TIME != tcp_keepalive_time) {
        flom_config_set_tcp_keepalive_time(NULL, tcp_keepalive_time);
    }
    if (_DEFAULT_TCP_KEEPALIVE_INTVL != tcp_keepalive_intvl) {
        flom_config_set_tcp_keepalive_intvl(NULL, tcp_keepalive_intvl);
    }
    if (_DEFAULT_TCP_KEEPALIVE_PROBES != tcp_keepalive_probes) {
        flom_config_set_tcp_keepalive_probes(NULL, tcp_keepalive_probes);
    }
    if (NULL != flom_config_get_command_trace_file(NULL))
        /* change trace destination if necessary */
        FLOM_TRACE_REOPEN(flom_config_get_command_trace_file(NULL));

    /* print configuration */
    if (flom_config_get_verbose(NULL))
        flom_config_print(NULL);

    /* check configuration */
    if (FLOM_RC_OK != (ret_cod = flom_config_check(NULL))) {
        g_warning("Configuration is not valid, cannot go on!\n");
        exit(FLOM_ES_GENERIC_ERROR);        
    }

    /* check if the command is asking daemon termination */
    if (quiesce_exit || immediate_exit) {
        g_print("Starting FLoM daemon %s shutdown...\n",
                immediate_exit ? "immediate" : "quiesce");
        flom_client_shutdown(NULL, immediate_exit);
        exit(0);
    }
    
    /* check the command is not null */
    if (NULL == command_argv) {
        g_warning("No command to execute!\n");
        exit(FLOM_ES_UNABLE_TO_EXECUTE_COMMAND);        
    }

    /* open connection to a valid flom lock manager... */
    if (FLOM_RC_OK != (ret_cod = flom_client_connect(NULL, &cd, TRUE))) {
        g_print("flom_client_connect: ret_cod=%d (%s)\n",
                ret_cod, flom_strerror(ret_cod));
        exit(FLOM_ES_GENERIC_ERROR);
    }

    /* sending lock command */
    ret_cod = flom_client_lock(NULL, &cd,
                               flom_config_get_resource_timeout(NULL),
                               locked_element, sizeof(locked_element));
    switch (ret_cod) {
        case FLOM_RC_OK: /* OK, go on */
            if (flom_config_get_verbose(NULL) && '\0' != locked_element[0])
                g_print("Locked element is '%s'\n", locked_element);
            break;
        case FLOM_RC_LOCK_BUSY: /* busy */
            g_print("Resource already locked, the lock cannot be obtained\n");
            /* gracefully disconnect from daemon */
            if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(&cd))) {
                g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                        ret_cod, flom_strerror(ret_cod));
            }
            exit(FLOM_ES_RESOURCE_BUSY);
            break;
        case FLOM_RC_LOCK_CANT_WAIT: /* can't wait, leaving... */
            g_print("The resource could be available in the future, but the "
                    "requester can't wait\n");
            /* gracefully disconnect from daemon */
            if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(&cd))) {
                g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                        ret_cod, flom_strerror(ret_cod));
            }
            exit(FLOM_ES_REQUESTER_CANT_WAIT);
            break;
        case FLOM_RC_LOCK_IMPOSSIBLE: /* impossible */
            g_print("Resource will never satisfy the request, the lock "
                    "cannot be obtained\n");
            /* gracefully disconnect from daemon */
            if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(&cd))) {
                g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                        ret_cod, flom_strerror(ret_cod));
            }
            exit(FLOM_ES_GENERIC_ERROR);
            break;
        case FLOM_RC_NETWORK_TIMEOUT: /* timeout expired, busy resource */
            g_print("The lock was not obtained because timeout "
                    "(%d milliseconds) expired\n",
                    flom_config_get_resource_timeout(NULL));
            /* gracefully disconnect from daemon */
            if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(&cd))) {
                g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                        ret_cod, flom_strerror(ret_cod));
            }
            exit(FLOM_ES_RESOURCE_BUSY);
            break;            
        default:
            g_print("flom_client_lock: ret_cod=%d (%s)\n",
                    ret_cod, flom_strerror(ret_cod));
            exit(FLOM_ES_GENERIC_ERROR);
    } /* switch (ret_cod) */

    /* execute the command */
    if (FLOM_RC_OK != (ret_cod = flom_exec(command_argv, locked_element,
                                           &child_status))) {
        guint i, num;
        g_print("Unable to execute command: '");
        num = g_strv_length(command_argv);
        for (i=0; i<num; ++i)
            g_print("%s", command_argv[i]);
        g_print("'\n");
        exit(FLOM_ES_UNABLE_TO_EXECUTE_COMMAND);
    }
    
    /* sending unlock command */
    if (FLOM_RC_OK != (ret_cod = flom_client_unlock(NULL, &cd))) {
        g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                ret_cod, flom_strerror(ret_cod));
        exit(FLOM_ES_GENERIC_ERROR);
    }

    /* gracefully disconnect from daemon */
    if (FLOM_RC_OK != (ret_cod = flom_client_disconnect(&cd))) {
        g_print("flom_client_unlock: ret_cod=%d (%s)\n",
                ret_cod, flom_strerror(ret_cod));
    }

    g_strfreev (command_argv);
    command_argv = NULL;

    /* release config data */
    flom_config_free(NULL);
    /* release regular expression data */
    global_res_name_preg_free();
    
	return child_status;
}