Blame libiscsi/libiscsi.h

Packit Service 37dbff
/*
Packit Service 37dbff
 * iSCSI Administration library
Packit Service 37dbff
 *
Packit Service 37dbff
 * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
Packit Service 37dbff
 * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
Packit Service 44d698
 * Copyright (C) 2015      Peter Hatina <phatina@redhat.com>
Packit Service 37dbff
 * maintained by open-iscsi@googlegroups.com
Packit Service 37dbff
 *
Packit Service 37dbff
 * This program is free software; you can redistribute it and/or modify
Packit Service 37dbff
 * it under the terms of the GNU General Public License as published
Packit Service 37dbff
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service 37dbff
 * (at your option) any later version.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This program is distributed in the hope that it will be useful, but
Packit Service 37dbff
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 37dbff
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit Service 37dbff
 * General Public License for more details.
Packit Service 37dbff
 *
Packit Service 37dbff
 * See the file COPYING included with this distribution for more details.
Packit Service 37dbff
 */
Packit Service 37dbff
Packit Service 37dbff
#ifndef __LIBISCSI_H
Packit Service 37dbff
#define __LIBISCSI_H
Packit Service 37dbff
Packit Service 37dbff
#include <netdb.h>
Packit Service 37dbff
Packit Service 37dbff
#ifdef __cplusplus
Packit Service 37dbff
extern "C" {
Packit Service 37dbff
#endif /* __cplusplus */
Packit Service 37dbff
Packit Service 37dbff
#if __GNUC__ >= 4
Packit Service 37dbff
#define PUBLIC __attribute__ ((visibility("default")))
Packit Service 37dbff
#else
Packit Service 37dbff
#define PUBLIC
Packit Service 37dbff
#endif
Packit Service 37dbff
Packit Service 37dbff
/** \brief Maximum length for iSCSI values.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Maximum length for iSCSI values such as hostnames and parameter values.
Packit Service 37dbff
 */
Packit Service 37dbff
#define LIBISCSI_VALUE_MAXLEN 256
Packit Service 37dbff
Packit Service 37dbff
/** \brief supported authentication methods
Packit Service 37dbff
 *
Packit Service 37dbff
 * This enum lists all supported authentication methods.
Packit Service 37dbff
 */
Packit Service 37dbff
enum libiscsi_auth_t {
Packit Service 37dbff
    libiscsi_auth_none   /** No authentication */,
Packit Service 37dbff
    libiscsi_auth_chap   /** CHAP authentication */,
Packit Service 37dbff
};
Packit Service 37dbff
Packit Service 37dbff
/** \brief libiscsi context struct
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note: even though libiscsi uses a context struct, the underlying open-iscsi
Packit Service 37dbff
 * code does not, so libiscsi is not thread safe, not even when using one
Packit Service 37dbff
 * context per thread!
Packit Service 37dbff
 */
Packit Service 37dbff
struct libiscsi_context;
Packit Service 37dbff
Packit Service 44d698
/** \brief iSCSI session timeouts
Packit Service 44d698
 *
Packit Service 44d698
 * Struct holding session timeouts.
Packit Service 44d698
 */
Packit Service 44d698
struct libiscsi_session_timeout {
Packit Service 44d698
    int abort_tmo;
Packit Service 44d698
    int lu_reset_tmo;
Packit Service 44d698
    int recovery_tmo;
Packit Service 44d698
    int tgt_reset_tmo;
Packit Service 44d698
};
Packit Service 44d698
Packit Service 37dbff
/** \brief iSCSI node record
Packit Service 37dbff
 *
Packit Service 37dbff
 * Struct holding data uniquely identifying an iSCSI node.
Packit Service 37dbff
 */
Packit Service 37dbff
struct libiscsi_node {
Packit Service 37dbff
    char name[LIBISCSI_VALUE_MAXLEN]     /** iSCSI iqn for the node. */;
Packit Service 37dbff
    int tpgt                             /** Portal group number. */;
Packit Service 37dbff
    /* Note open-iscsi has some code in place for multiple connections in one
Packit Service 37dbff
       node record and thus multiple address / port combi's, but this does not
Packit Service 37dbff
       get used anywhere, so we keep things simple and assume one connection */
Packit Service 37dbff
    char address[NI_MAXHOST]             /** Portal hostname or IP-address. */;
Packit Service 37dbff
    int port                             /** Portal port number. */;
Packit Service 37dbff
    char iface[LIBISCSI_VALUE_MAXLEN]    /** Interface to connect through. */;
Packit Service 37dbff
};
Packit Service 37dbff
Packit Service 37dbff
/** \brief libiscsi CHAP authentication information struct
Packit Service 37dbff
 *
Packit Service 37dbff
 * Struct holding all data needed for CHAP login / authentication. Note that
Packit Service 37dbff
 * \e reverse_username may be a 0 length string in which case only forward
Packit Service 37dbff
 * authentication will be done.
Packit Service 37dbff
 */
Packit Service 37dbff
struct libiscsi_chap_auth_info {
Packit Service 37dbff
    char username[LIBISCSI_VALUE_MAXLEN]         /** Username */;
Packit Service 37dbff
    char password[LIBISCSI_VALUE_MAXLEN]         /** Password */;
Packit Service 37dbff
    char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */;
Packit Service 37dbff
    char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */;
Packit Service 37dbff
};
Packit Service 37dbff
Packit Service 44d698
/** \brief iSCSI session
Packit Service 44d698
 *
Packit Service 44d698
 * Struct hoding iSCSI session information.
Packit Service 44d698
 */
Packit Service 44d698
struct libiscsi_session_info {
Packit Service 44d698
    int sid;
Packit Service 44d698
Packit Service 44d698
    struct libiscsi_session_timeout tmo;
Packit Service 44d698
    struct libiscsi_chap_auth_info chap;
Packit Service 44d698
Packit Service 44d698
    char targetname[LIBISCSI_VALUE_MAXLEN];
Packit Service 44d698
    int tpgt;
Packit Service 44d698
    char address[NI_MAXHOST];
Packit Service 44d698
    int port;
Packit Service 44d698
    char persistent_address[NI_MAXHOST];
Packit Service 44d698
    int persistent_port;
Packit Service 44d698
};
Packit Service 44d698
Packit Service 37dbff
/** \brief generic libiscsi authentication information struct
Packit Service 37dbff
 *
Packit Service 37dbff
 * Struct holding authentication information for discovery and login.
Packit Service 37dbff
 */
Packit Service 37dbff
struct libiscsi_auth_info {
Packit Service 37dbff
    enum libiscsi_auth_t method /** Authentication method to use */;
Packit Service 37dbff
    union {
Packit Service 37dbff
        struct libiscsi_chap_auth_info chap /** Chap specific info */;
Packit Service 37dbff
    } /** Union holding method depenend info */;
Packit Service 37dbff
};
Packit Service 37dbff
Packit Service 37dbff
/** \brief Initalize libiscsi
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function creates a libiscsi context and initalizes it. This context
Packit Service 37dbff
 * is need to use other libiscsi funtions.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \return     A pointer to the created context, or NULL in case of an error.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC struct libiscsi_context *libiscsi_init(void);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Cleanup libiscsi used resource
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function cleanups any used resources and then destroys the passed
Packit Service 37dbff
 * context. After this the passed in context may no longer be used!
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC void libiscsi_cleanup(struct libiscsi_context *context);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Discover iSCSI nodes using sendtargets and add them to the node db.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function connects to the given address and port and then tries to
Packit Service 37dbff
 * discover iSCSI nodes using the sendtargets protocol. Any found nodes are
Packit Service 37dbff
 * added to the local iSCSI node database and are returned in a dynamically
Packit Service 37dbff
 * allocated array.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note that the (optional) authentication info is for authenticating the
Packit Service 37dbff
 * discovery, and is not for the found nodes! If the connection(s) to the
Packit Service 37dbff
 * node(s) need authentication too, you can set the username / password for
Packit Service 37dbff
 * those (which can be different!) using the libiscsi_node_set_auth() function.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 * \param address                Hostname or IP-address to connect to.
Packit Service 37dbff
 * \param port                   Port to connect to, or 0 for the default port.
Packit Service 37dbff
 * \param auth_info              Authentication information, or NULL.
Packit Service 37dbff
 * \param nr_found		 The number of found nodes will be returned
Packit Service 37dbff
 *                               through this pointer if not NULL.
Packit Service 37dbff
 * \param found_nodes            The address of the dynamically allocated array
Packit Service 37dbff
 *                               of found nodes will be returned through this
Packit Service 37dbff
 *                               pointer if not NULL. The caller must free this
Packit Service 37dbff
 *                               array using free().
Packit Service 37dbff
 * \return                       0 on success, otherwise a standard error code
Packit Service 37dbff
 *                               (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context,
Packit Service 37dbff
    const char *address, int port, const struct libiscsi_auth_info *auth_info,
Packit Service 37dbff
    int *nr_found, struct libiscsi_node **found_nodes);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Read iSCSI node info from firmware and add them to the node db.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found
Packit Service 37dbff
 * nodes are added to the local iSCSI node database and are returned in a
Packit Service 37dbff
 * dynamically allocated array.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note that unlike sendtargets discovery, this function will also read
Packit Service 37dbff
 * authentication info and store that in the database too.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note this function currently is a stub which will always return -EINVAL
Packit Service 37dbff
 * (IOW it is not yet implemented)
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 * \param nr_found		 The number of found nodes will be returned
Packit Service 37dbff
 *                               through this pointer if not NULL.
Packit Service 37dbff
 * \param found_nodes            The address of the dynamically allocated array
Packit Service 37dbff
 *                               of found nodes will be returned through this
Packit Service 37dbff
 *                               pointer if not NULL. The caller must free this
Packit Service 37dbff
 *                               array using free().
Packit Service 37dbff
 * \return                       0 on success, otherwise a standard error code
Packit Service 37dbff
 *                               (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context,
Packit Service 37dbff
    int *nr_found, struct libiscsi_node **found_nodes);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Check validity of the given authentication info.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function checks the validity of the given authentication info. For 
Packit Service 37dbff
 * example in case of CHAP, if the username and password are not empty.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function is mainly intended for use by language bindings.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 * \param auth_info              Authentication information to check.
Packit Service 37dbff
 * \return                       0 on success, otherwise EINVAL.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context,
Packit Service 37dbff
	const struct libiscsi_auth_info *auth_info);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Set the authentication info for the given node.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function sets the authentication information for the node described by
Packit Service 37dbff
 * the given node record. This will overwrite any existing authentication
Packit Service 37dbff
 * information.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This is the way to specify authentication information for nodes found
Packit Service 37dbff
 * through sendtargets discovery.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note:
Packit Service 37dbff
 * 1) This is a convience wrapper around libiscsi_node_set_parameter(),
Packit Service 37dbff
 *    setting the node.session.auth.* parameters.
Packit Service 37dbff
 * 2) For nodes found through firmware discovery the authentication information
Packit Service 37dbff
 *    has already been set from the firmware.
Packit Service 37dbff
 * 3) \e auth_info may be NULL in which case any existing authinfo will be
Packit Service 37dbff
 *    cleared.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 * \param node                   iSCSI node to set auth information of
Packit Service 37dbff
 * \param auth_info              Authentication information, or NULL.
Packit Service 37dbff
 * \return                       0 on success, otherwise a standard error code
Packit Service 37dbff
 *                               (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node,
Packit Service 37dbff
    const struct libiscsi_auth_info *auth_info);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Get the authentication info for the given node.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function gets the authentication information for the node described by
Packit Service 37dbff
 * the given node record.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context                libiscsi context to operate on.
Packit Service 37dbff
 * \param node                   iSCSI node to set auth information of
Packit Service 37dbff
 * \param auth_info              Pointer to a libiscsi_auth_info struct where
Packit Service 37dbff
 *                               the retreived information will be stored.
Packit Service 37dbff
 * \return                       0 on success, otherwise a standard error code
Packit Service 37dbff
 *                               (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node,
Packit Service 37dbff
    struct libiscsi_auth_info *auth_info);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Login to an iSCSI node.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Login to the iSCSI node described by the given node record.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context       libiscsi context to operate on.
Packit Service 37dbff
 * \param node          iSCSI node to login to.
Packit Service 37dbff
 * \return              0 on success, otherwise a standard error code
Packit Service 37dbff
 *                      (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_login(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Logout of an iSCSI node.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Logout of the iSCSI node described by the given node record.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context       libiscsi context to operate on.
Packit Service 37dbff
 * \param node          iSCSI node to logout from.
Packit Service 37dbff
 * \return              0 on success, otherwise a standard error code
Packit Service 37dbff
 *                      (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_logout(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node);
Packit Service 37dbff
Packit Service 44d698
/** \brief Get an array of iSCSI sessions.
Packit Service 44d698
 *
Packit Service 44d698
 * Get the array containing iSCSI sessions' information.
Packit Service 44d698
 *
Packit Service 44d698
 * \param context       libiscsi context to operate on.
Packit Service 44d698
 * \param infos         Array of iSCSI sessions' information.
Packit Service 44d698
 *                      Release with free().
Packit Service 44d698
 * \param nr_sessions   The number of elements in \e infos.
Packit Service 44d698
 * \return              0 on success, otherwise a standard error code
Packit Service 44d698
 *                      (from errno.h).
Packit Service 44d698
 */
Packit Service 44d698
PUBLIC int libiscsi_get_session_infos(struct libiscsi_context *context,
Packit Service 44d698
    struct libiscsi_session_info **infos, int *nr_sessions);
Packit Service 44d698
Packit Service 44d698
/** \brief Get session information by session ID.
Packit Service 44d698
 *
Packit Service 44d698
 * \param context       libiscsi context to operate on.
Packit Service 44d698
 * \param info          iSCSI session information.
Packit Service 44d698
 * \param session       Session name.
Packit Service 44d698
 * \return              0 on success, otherwise a standard error code
Packit Service 44d698
 *                      (from errno.h)
Packit Service 44d698
 */
Packit Service 44d698
PUBLIC int libiscsi_get_session_info_by_id(struct libiscsi_context *context,
Packit Service 44d698
    struct libiscsi_session_info *info,
Packit Service 44d698
    const char *session);
Packit Service 44d698
Packit Service 37dbff
/** \brief Set an iSCSI parameter for the given node
Packit Service 37dbff
 *
Packit Service 37dbff
 * Set the given nodes iSCSI parameter named by \e parameter to value \e value.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context       libiscsi context to operate on.
Packit Service 37dbff
 * \param node          iSCSI node to change a parameter from.
Packit Service 37dbff
 * \param parameter     Name of the parameter to set.
Packit Service 37dbff
 * \param value         Value to set the parameter too.
Packit Service 37dbff
 * \return              0 on success, otherwise a standard error code
Packit Service 37dbff
 *                      (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node,
Packit Service 37dbff
    const char *parameter, const char *value);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Get the value of an iSCSI parameter for the given node
Packit Service 37dbff
 *
Packit Service 37dbff
 * Get the value of the given nodes iSCSI parameter named by \e parameter.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context       libiscsi context to operate on.
Packit Service 37dbff
 * \param node          iSCSI node to change a parameter from.
Packit Service 37dbff
 * \param parameter     Name of the parameter to get.
Packit Service 37dbff
 * \param value         The retreived value is stored here, this buffer must be
Packit Service 37dbff
 *                      atleast LIBISCSI_VALUE_MAXLEN bytes large.
Packit Service 37dbff
 * \return              0 on success, otherwise a standard error code
Packit Service 37dbff
 *                      (from errno.h).
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context,
Packit Service 37dbff
    const struct libiscsi_node *node, const char *parameter, char *value);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Get human readable string describing the last libiscsi error.
Packit Service 37dbff
 *
Packit Service 37dbff
 * This function can be called to get a human readable error string when a
Packit Service 37dbff
 * libiscsi function has returned an error. This function uses a single buffer
Packit Service 37dbff
 * per context, thus the result is only valid as long as no other libiscsi
Packit Service 37dbff
 * calls are made on the same context after the failing function call.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param context       libiscsi context to operate on.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \return human readable string describing the last libiscsi error.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context);
Packit Service 37dbff
Packit Service 37dbff
Packit Service 37dbff
/************************** Utility functions *******************************/
Packit Service 37dbff
Packit Service 37dbff
/** \brief libiscsi network config struct
Packit Service 37dbff
 *
Packit Service 37dbff
 * libiscsi network config struct.
Packit Service 37dbff
 */
Packit Service 37dbff
struct libiscsi_network_config {
Packit Service 37dbff
    int dhcp                                  /** Using DHCP? (boolean). */;
Packit Service 37dbff
    char iface_name[LIBISCSI_VALUE_MAXLEN]    /** Interface name. */;
Packit Service 37dbff
    char mac_address[LIBISCSI_VALUE_MAXLEN]   /** MAC address. */;
Packit Service 37dbff
    char ip_address[LIBISCSI_VALUE_MAXLEN]    /** IP address. */;
Packit Service 37dbff
    char netmask[LIBISCSI_VALUE_MAXLEN]       /** Netmask. */;
Packit Service 37dbff
    char gateway[LIBISCSI_VALUE_MAXLEN]       /** IP of Default gateway. */;
Packit Service 37dbff
    char primary_dns[LIBISCSI_VALUE_MAXLEN]   /** IP of the Primary DNS. */;
Packit Service 37dbff
    char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */;
Packit Service 37dbff
};
Packit Service 37dbff
Packit Service 37dbff
/** \brief Get network configuration information from iscsi firmware
Packit Service 37dbff
 *
Packit Service 37dbff
 * Function can be called to get the network configuration information
Packit Service 37dbff
 * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a
Packit Service 37dbff
 * network adapter with iscsi boot firmware.
Packit Service 37dbff
 *
Packit Service 37dbff
 * Note that not all fields of the returned struct are necessarilly filled,
Packit Service 37dbff
 * unset fields contain a 0 length string.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param config        pointer to a libiscsi_network_config struct to fill.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \return              0 on success, ENODEV when no iscsi firmware was found.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_get_firmware_network_config(
Packit Service 37dbff
    struct libiscsi_network_config *config);
Packit Service 37dbff
Packit Service 37dbff
/** \brief Get the initiator name (iqn) from the iscsi firmware
Packit Service 37dbff
 *
Packit Service 37dbff
 * Get the initiator name (iqn) from the iscsi firmware.
Packit Service 37dbff
 *
Packit Service 37dbff
 * \param initiatorname The initiator name is stored here, this buffer must be
Packit Service 37dbff
 *                      atleast LIBISCSI_VALUE_MAXLEN bytes large.
Packit Service 37dbff
 * \return              0 on success, ENODEV when no iscsi firmware was found.
Packit Service 37dbff
 */
Packit Service 37dbff
PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname);
Packit Service 37dbff
Packit Service 37dbff
#undef PUBLIC
Packit Service 37dbff
Packit Service 37dbff
#ifdef __cplusplus
Packit Service 37dbff
}
Packit Service 37dbff
#endif /* __cplusplus */
Packit Service 37dbff
Packit Service 37dbff
#endif