Coverage Report

Created: 2026-01-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pacemaker/include/crm/lrmd.h
Line
Count
Source
1
/*
2
 * Copyright 2012-2025 the Pacemaker project contributors
3
 *
4
 * The version control history for this file may have further details.
5
 *
6
 * This source code is licensed under the GNU Lesser General Public License
7
 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8
 */
9
10
#ifndef PCMK__CRM_LRMD__H
11
#  define PCMK__CRM_LRMD__H
12
13
#include <stdbool.h>      // bool
14
#include <stdint.h>       // UINT32_C
15
#include <glib.h>         // guint, GList
16
#include <crm_config.h>
17
#include <crm/lrmd_events.h>
18
#include <crm/services.h>
19
20
#include <crm/common/internal.h>    // pcmk__compare_versions()
21
22
#ifdef __cplusplus
23
extern "C" {
24
#endif
25
26
/**
27
 * \file
28
 * \brief Resource agent executor
29
 * \ingroup lrmd
30
 */
31
32
typedef struct lrmd_s lrmd_t;
33
typedef struct lrmd_key_value_s {
34
    char *key;
35
    char *value;
36
    struct lrmd_key_value_s *next;
37
} lrmd_key_value_t;
38
39
/* The major version should be bumped every time there is an incompatible
40
 * change that prevents older clients from connecting to this version of
41
 * the server.  The minor version indicates feature support.
42
 *
43
 * Protocol  Pacemaker  Significant changes
44
 * --------  ---------  -------------------
45
 *   1.2       2.1.8    PCMK__CIB_REQUEST_SCHEMAS
46
 */
47
#define LRMD_PROTOCOL_VERSION "1.2"
48
49
#define LRMD_SUPPORTS_SCHEMA_XFER(x) (pcmk__compare_versions((x), "1.2") >= 0)
50
51
/* The major protocol version the client and server both need to support for
52
 * the connection to be successful.  This should only ever be the major
53
 * version - not a complete version number.
54
 */
55
#define LRMD_COMPATIBLE_PROTOCOL "1"
56
57
/* *INDENT-OFF* */
58
#define DEFAULT_REMOTE_KEY_LOCATION PACEMAKER_CONFIG_DIR "/authkey"
59
0
#define DEFAULT_REMOTE_PORT 3121
60
0
#define DEFAULT_REMOTE_USERNAME "lrmd"
61
62
#define LRMD_OP_RSC_REG           "lrmd_rsc_register"
63
#define LRMD_OP_RSC_EXEC          "lrmd_rsc_exec"
64
#define LRMD_OP_RSC_CANCEL        "lrmd_rsc_cancel"
65
#define LRMD_OP_RSC_UNREG         "lrmd_rsc_unregister"
66
#define LRMD_OP_RSC_INFO          "lrmd_rsc_info"
67
#define LRMD_OP_RSC_METADATA      "lrmd_rsc_metadata"
68
#define LRMD_OP_POKE              "lrmd_rsc_poke"
69
#define LRMD_OP_NEW_CLIENT        "lrmd_rsc_new_client"
70
#define LRMD_OP_CHECK             "lrmd_check"
71
#define LRMD_OP_ALERT_EXEC        "lrmd_alert_exec"
72
#define LRMD_OP_GET_RECURRING     "lrmd_get_recurring"
73
74
#define LRMD_IPC_OP_NEW           "new"
75
#define LRMD_IPC_OP_DESTROY       "destroy"
76
#define LRMD_IPC_OP_EVENT         "event"
77
#define LRMD_IPC_OP_REQUEST       "request"
78
#define LRMD_IPC_OP_RESPONSE      "response"
79
#define LRMD_IPC_OP_SHUTDOWN_REQ  "shutdown_req"
80
#define LRMD_IPC_OP_SHUTDOWN_ACK  "shutdown_ack"
81
#define LRMD_IPC_OP_SHUTDOWN_NACK "shutdown_nack"
82
/* *INDENT-ON* */
83
84
/*!
85
 * \brief Create a new connection to the local executor
86
 */
87
lrmd_t *lrmd_api_new(void);
88
89
/*!
90
 * \brief Create a new TLS connection to a remote executor
91
 *
92
 * \param[in] nodename  Name of remote node identified with this connection
93
 * \param[in] server    Hostname to connect to
94
 * \param[in] port      Port number to connect to (or 0 to use default)
95
 *
96
 * \return Newly created executor connection object
97
 * \note If only one of \p nodename and \p server is non-NULL, it will be used
98
 *       for both purposes. If both are NULL, a local IPC connection will be
99
 *       created instead.
100
 */
101
lrmd_t *lrmd_remote_api_new(const char *nodename, const char *server, int port);
102
103
/*!
104
 * \brief Use after lrmd_poll returns 1 to read and dispatch a message
105
 *
106
 * \param[in,out] lrmd  Executor connection object
107
 *
108
 * \return TRUE if connection is still up, FALSE if disconnected
109
 */
110
bool lrmd_dispatch(lrmd_t *lrmd);
111
112
/*!
113
 * \brief Check whether a message is available on an executor connection
114
 *
115
 * \param[in,out] lrmd     Executor connection object to check
116
 * \param[in]     timeout  Currently ignored
117
 *
118
 * \retval 1               Message is ready
119
 * \retval 0               Timeout occurred
120
 * \retval negative errno  Error occurred
121
 *
122
 * \note This is intended for callers that do not use a main loop.
123
 */
124
int lrmd_poll(lrmd_t *lrmd, int timeout);
125
126
/*!
127
 * \brief Destroy executor connection object
128
 *
129
 * \param[in,out] lrmd     Executor connection object to destroy
130
 */
131
void lrmd_api_delete(lrmd_t *lrmd);
132
133
lrmd_key_value_t *lrmd_key_value_add(lrmd_key_value_t * kvp, const char *key, const char *value);
134
135
enum lrmd_call_options {
136
    lrmd_opt_none                   = 0,
137
138
    /*!
139
     * Drop recurring operations initiated by a client when the client
140
     * disconnects. This option is only valid when registering a resource. When
141
     * used with a connection to a remote executor, recurring operations will be
142
     * dropped once all remote connections disconnect.
143
     */
144
    lrmd_opt_drop_recurring         = (UINT32_C(1) << 0),
145
146
    //! Notify only the client that made the request (rather than all clients)
147
    lrmd_opt_notify_orig_only       = (UINT32_C(1) << 1),
148
149
    //! Send notifications for recurring operations only when the result changes
150
    lrmd_opt_notify_changes_only    = (UINT32_C(1) << 2),
151
};
152
153
typedef struct lrmd_rsc_info_s {
154
    char *id;
155
    char *type;
156
    char *standard;
157
    char *provider;
158
} lrmd_rsc_info_t;
159
160
typedef struct lrmd_op_info_s {
161
    char *rsc_id;
162
    char *action;
163
    char *interval_ms_s;
164
    char *timeout_ms_s;
165
} lrmd_op_info_t;
166
167
lrmd_rsc_info_t *lrmd_new_rsc_info(const char *rsc_id, const char *standard,
168
                                   const char *provider, const char *type);
169
lrmd_rsc_info_t *lrmd_copy_rsc_info(lrmd_rsc_info_t * rsc_info);
170
void lrmd_free_rsc_info(lrmd_rsc_info_t * rsc_info);
171
void lrmd_free_op_info(lrmd_op_info_t *op_info);
172
173
typedef void (*lrmd_event_callback) (lrmd_event_data_t * event);
174
175
typedef struct lrmd_list_s {
176
    const char *val;
177
    struct lrmd_list_s *next;
178
} lrmd_list_t;
179
180
void lrmd_list_freeall(lrmd_list_t * head);
181
void lrmd_key_value_freeall(lrmd_key_value_t * head);
182
183
typedef struct lrmd_api_operations_s {
184
    /*!
185
     * \brief Connect to an executor
186
     *
187
     * \param[in,out] lrmd         Executor connection object
188
     * \param[in]     client_name  Arbitrary identifier to pass to server
189
     * \param[out]    fd           If not NULL, where to store file descriptor
190
     *                             for connection's socket
191
     *
192
     * \return Legacy Pacemaker return code
193
     */
194
    int (*connect) (lrmd_t *lrmd, const char *client_name, int *fd);
195
196
    /*!
197
     * \brief Initiate an executor connection without blocking
198
     *
199
     * \param[in,out] lrmd         Executor connection object
200
     * \param[in]     client_name  Arbitrary identifier to pass to server
201
     * \param[in]     timeout      Error if not connected within this time
202
     *                             (milliseconds)
203
     *
204
     * \return Legacy Pacemaker return code (if pcmk_ok, the event callback will
205
     *         be called later with the result)
206
     * \note This function requires a mainloop.
207
     */
208
    int (*connect_async) (lrmd_t *lrmd, const char *client_name,
209
                          int timeout /*ms */ );
210
211
    /*!
212
     * \brief Check whether connection to executor daemon is (still) active
213
     *
214
     * \param[in,out] lrmd  Executor connection object to check
215
     *
216
     * \return 1 if the executor connection is active, 0 otherwise
217
     */
218
    int (*is_connected) (lrmd_t *lrmd);
219
220
    /*!
221
     * \brief Poke executor connection to verify it is still active
222
     *
223
     * \param[in,out] lrmd  Executor connection object to check
224
     *
225
     * \return Legacy Pacemaker return code (if pcmk_ok, the event callback will
226
     *         be called later with the result)
227
     * \note The response comes in the form of a poke event to the callback.
228
     *
229
     */
230
    int (*poke_connection) (lrmd_t *lrmd);
231
232
    /*!
233
     * \brief Disconnect from the executor.
234
     *
235
     * \param[in,out] lrmd  Executor connection object to disconnect
236
     *
237
     * \return Legacy Pacemaker return code
238
     */
239
    int (*disconnect) (lrmd_t *lrmd);
240
241
    /*!
242
     * \brief Register a resource with the executor
243
     *
244
     * \param[in,out] lrmd      Executor connection object
245
     * \param[in]     rsc_id    ID of resource to register
246
     * \param[in]     standard  Resource's resource agent standard
247
     * \param[in]     provider  Resource's resource agent provider (or NULL)
248
     * \param[in]     agent     Resource's resource agent name
249
     * \param[in]     options   Group of enum lrmd_call_options flags
250
     *
251
     * \note Synchronous, guaranteed to occur in daemon before function returns.
252
     *
253
     * \return Legacy Pacemaker return code
254
     */
255
    int (*register_rsc) (lrmd_t *lrmd, const char *rsc_id, const char *standard,
256
                         const char *provider, const char *agent,
257
                         enum lrmd_call_options options);
258
259
    /*!
260
     * \brief Retrieve a resource's registration information
261
     *
262
     * \param[in,out] lrmd      Executor connection object
263
     * \param[in]     rsc_id    ID of resource to check
264
     * \param[in]     options   Group of enum lrmd_call_options flags
265
     *
266
     * \return Resource information on success, otherwise NULL
267
     */
268
    lrmd_rsc_info_t *(*get_rsc_info) (lrmd_t *lrmd, const char *rsc_id,
269
                                      enum lrmd_call_options options);
270
271
    /*!
272
     * \brief Retrieve recurring operations registered for a resource
273
     *
274
     * \param[in,out] lrmd        Executor connection object
275
     * \param[in]     rsc_id      ID of resource to check
276
     * \param[in]     timeout_ms  Error if not completed within this time
277
     * \param[in]     options     Group of enum lrmd_call_options flags
278
     * \param[out]    output      Where to store list of lrmd_op_info_t
279
     *
280
     * \return Legacy Pacemaker return code
281
     */
282
    int (*get_recurring_ops) (lrmd_t *lrmd, const char *rsc_id, int timeout_ms,
283
                              enum lrmd_call_options options, GList **output);
284
285
    /*!
286
     * \brief Unregister a resource from the executor
287
     *
288
     * \param[in,out] lrmd     Executor connection object
289
     * \param[in]     rsc_id   ID of resource to unregister
290
     * \param[in]     options  Group of enum lrmd_call_options flags
291
     *
292
     * \return Legacy Pacemaker return code (of particular interest, EINPROGRESS
293
     *         means that operations are in progress for the resource, and the
294
     *         unregistration will be done when they complete)
295
     * \note Pending and recurring operations will be cancelled.
296
     * \note Synchronous, guaranteed to occur in daemon before function returns.
297
     *
298
     */
299
    int (*unregister_rsc) (lrmd_t *lrmd, const char *rsc_id,
300
                           enum lrmd_call_options options);
301
302
    /*!
303
     * \brief Set a callback for executor events
304
     *
305
     * \param[in,out] lrmd      Executor connection object
306
     * \param[in]     callback  Callback to set
307
     */
308
    void (*set_callback) (lrmd_t *lrmd, lrmd_event_callback callback);
309
310
    /*!
311
     * \brief Request execution of a resource action
312
     *
313
     * \param[in,out] lrmd         Executor connection object
314
     * \param[in]     rsc_id       ID of resource
315
     * \param[in]     action       Name of resource action to execute
316
     * \param[in]     userdata     Arbitrary string to pass to event callback
317
     * \param[in]     interval_ms  If 0, execute action once, otherwise
318
     *                             recurring at this interval (in milliseconds)
319
     * \param[in]     timeout      Error if not complete within this time (in
320
     *                             milliseconds)
321
     * \param[in]     start_delay  Wait this long before execution (in
322
     *                             milliseconds)
323
     * \param[in]     options      Group of enum lrmd_call_options flags
324
     * \param[in,out] params       Parameters to pass to agent (will be freed)
325
     *
326
     * \return A call ID for the action on success (in which case the action is
327
     *         queued in the executor, and the event callback will be called
328
     *         later with the result), otherwise a negative legacy Pacemaker
329
     *         return code
330
     * \note exec() and cancel() operations on an individual resource are
331
     *       guaranteed to occur in the order the client API is called. However,
332
     *       operations on different resources are not guaranteed to occur in
333
     *       any specific order.
334
     */
335
    int (*exec) (lrmd_t *lrmd, const char *rsc_id, const char *action,
336
                 const char *userdata, guint interval_ms, int timeout,
337
                 int start_delay, enum lrmd_call_options options,
338
                 lrmd_key_value_t *params);
339
340
    /*!
341
     * \brief Cancel a recurring resource action
342
     *
343
     * \param[in,out] lrmd         Executor connection object
344
     * \param[in]     rsc_id       ID of resource
345
     * \param[in]     action       Name of resource action to cancel
346
     * \param[in]     interval_ms  Action's interval (in milliseconds)
347
     *
348
     * \return Legacy Pacemaker return code (if pcmk_ok, cancellation is queued
349
     *         on function return, and the event callback will be called later
350
     *         with an exec_complete event with an lrmd_op_status signifying
351
     *         that the operation is cancelled)
352
     *
353
     * \note exec() and cancel() operations on an individual resource are
354
     *       guaranteed to occur in the order the client API is called. However,
355
     *       operations on different resources are not guaranteed to occur in
356
     *       any specific order.
357
     */
358
    int (*cancel) (lrmd_t *lrmd, const char *rsc_id, const char *action,
359
                   guint interval_ms);
360
361
    /*!
362
     * \brief Retrieve resource agent metadata synchronously
363
     *
364
     * \param[in]  lrmd      Executor connection (unused)
365
     * \param[in]  standard  Resource agent class
366
     * \param[in]  provider  Resource agent provider
367
     * \param[in]  agent     Resource agent type
368
     * \param[out] output    Where to store metadata (must not be NULL)
369
     * \param[in]  options   Group of enum lrmd_call_options flags (unused)
370
     *
371
     * \return Legacy Pacemaker return code
372
     *
373
     * \note Caller is responsible for freeing output. This call is always
374
     *       synchronous (blocking), and always done directly by the library
375
     *       (not via the executor connection). This means that it is based on
376
     *       the local host environment, even if the executor connection is to a
377
     *       remote node, so this may fail if the agent is not installed
378
     *       locally. This also means that, if an external agent must be
379
     *       executed, it will be executed by the caller's user, not the
380
     *       executor's.
381
     */
382
    int (*get_metadata) (lrmd_t *lrmd, const char *standard,
383
                         const char *provider, const char *agent,
384
                         char **output, enum lrmd_call_options options);
385
386
    /*!
387
     * \brief Retrieve a list of installed resource agents
388
     *
389
     * \param[in]  lrmd      Executor connection (unused)
390
     * \param[out] agents    Where to store agent list (must not be NULL)
391
     * \param[in]  standard  Resource agent standard to list
392
     * \param[in]  provider  Resource agent provider to list (or NULL)
393
     *
394
     * \return Number of items in list on success, negative legacy Pacemaker
395
     *         return code otherwise
396
     *
397
     * \note if standard is not provided, all known agents will be returned
398
     * \note list must be freed using lrmd_list_freeall()
399
     */
400
    int (*list_agents) (lrmd_t *lrmd, lrmd_list_t **agents,
401
                        const char *standard, const char *provider);
402
403
    /*!
404
     * \brief Retrieve a list of resource agent providers
405
     *
406
     * \param[in]  lrmd       Executor connection (unused)
407
     * \param[in]  agent      If not NULL, list providers for this agent only
408
     * \param[out] providers  Where to store provider list
409
     *
410
     * \return Number of items in list on success, negative legacy Pacemaker
411
     *         return code otherwise
412
     * \note The caller is responsible for freeing *providers with
413
     *       lrmd_list_freeall().
414
     */
415
    int (*list_ocf_providers) (lrmd_t *lrmd, const char *agent,
416
                               lrmd_list_t **providers);
417
418
    /*!
419
     * \brief Retrieve a list of supported standards
420
     *
421
     * \param[in]  lrmd       Executor connection (unused)
422
     * \param[out] standards  Where to store standards list
423
     *
424
     * \return Number of items in list on success, negative legacy Pacemaker
425
     *         return code otherwise
426
     * \note The caller is responsible for freeing *standards with
427
     *       lrmd_list_freeall().
428
     */
429
    int (*list_standards) (lrmd_t *lrmd, lrmd_list_t **standards);
430
431
    /*!
432
     * \brief Execute an alert agent
433
     *
434
     * \param[in,out] lrmd        Executor connection
435
     * \param[in]     alert_id    Name of alert to execute
436
     * \param[in]     alert_path  Full path to alert executable
437
     * \param[in]     timeout     Error if not complete within this many
438
     *                            milliseconds
439
     * \param[in,out] params      Parameters to pass to agent (will be freed)
440
     *
441
     * \return Legacy Pacemaker return code (if pcmk_ok, the alert is queued in
442
     *         the executor, and the event callback will be called later with
443
     *         the result)
444
     *
445
     * \note Operations on individual alerts (by ID) are guaranteed to occur in
446
     *       the order the client API is called. Operations on different alerts
447
     *       are not guaranteed to occur in any specific order.
448
     */
449
    int (*exec_alert) (lrmd_t *lrmd, const char *alert_id,
450
                       const char *alert_path, int timeout,
451
                       lrmd_key_value_t *params);
452
453
    /*!
454
     * \brief Retrieve resource agent metadata synchronously with parameters
455
     *
456
     * \param[in]     lrmd      Executor connection (unused)
457
     * \param[in]     standard  Resource agent class
458
     * \param[in]     provider  Resource agent provider
459
     * \param[in]     agent     Resource agent type
460
     * \param[out]    output    Where to store metadata (must not be NULL)
461
     * \param[in]     options   Group of enum lrmd_call_options flags (unused)
462
     * \param[in,out] params    Parameters to pass to agent (will be freed)
463
     *
464
     * \return Legacy Pacemaker return code
465
     *
466
     * \note This is identical to the get_metadata() API call, except parameters
467
     *       will be passed to the resource agent via environment variables.
468
     */
469
    int (*get_metadata_params) (lrmd_t *lrmd, const char *standard,
470
                                const char *provider, const char *agent,
471
                                char **output, enum lrmd_call_options options,
472
                                lrmd_key_value_t *params);
473
474
} lrmd_api_operations_t;
475
476
struct lrmd_s {
477
    lrmd_api_operations_t *cmds;
478
    void *lrmd_private;
479
};
480
481
static inline const char *
482
lrmd_event_type2str(enum lrmd_callback_event type)
483
0
{
484
0
    switch (type) {
485
0
        case lrmd_event_register:
486
0
            return "register";
487
0
        case lrmd_event_unregister:
488
0
            return "unregister";
489
0
        case lrmd_event_exec_complete:
490
0
            return "exec_complete";
491
0
        case lrmd_event_disconnect:
492
0
            return "disconnect";
493
0
        case lrmd_event_connect:
494
0
            return "connect";
495
0
        case lrmd_event_poke:
496
0
            return "poke";
497
0
        case lrmd_event_new_client:
498
0
            return "new_client";
499
0
    }
500
0
    return "unknown";
501
0
}
Unexecuted instantiation: results.c:lrmd_event_type2str
Unexecuted instantiation: scores.c:lrmd_event_type2str
Unexecuted instantiation: strings.c:lrmd_event_type2str
Unexecuted instantiation: utils.c:lrmd_event_type2str
Unexecuted instantiation: iso8601.c:lrmd_event_type2str
Unexecuted instantiation: logging.c:lrmd_event_type2str
Unexecuted instantiation: mainloop.c:lrmd_event_type2str
Unexecuted instantiation: options.c:lrmd_event_type2str
Unexecuted instantiation: output.c:lrmd_event_type2str
Unexecuted instantiation: output_log.c:lrmd_event_type2str
Unexecuted instantiation: output_text.c:lrmd_event_type2str
Unexecuted instantiation: output_xml.c:lrmd_event_type2str
Unexecuted instantiation: patchset_display.c:lrmd_event_type2str
Unexecuted instantiation: schemas.c:lrmd_event_type2str
Unexecuted instantiation: xml.c:lrmd_event_type2str
Unexecuted instantiation: xml_attr.c:lrmd_event_type2str
Unexecuted instantiation: xml_comment.c:lrmd_event_type2str
Unexecuted instantiation: xml_display.c:lrmd_event_type2str
Unexecuted instantiation: xml_element.c:lrmd_event_type2str
Unexecuted instantiation: xml_idref.c:lrmd_event_type2str
Unexecuted instantiation: xml_io.c:lrmd_event_type2str
Unexecuted instantiation: xpath.c:lrmd_event_type2str
Unexecuted instantiation: acl.c:lrmd_event_type2str
Unexecuted instantiation: actions.c:lrmd_event_type2str
Unexecuted instantiation: agents.c:lrmd_event_type2str
Unexecuted instantiation: cmdline.c:lrmd_event_type2str
Unexecuted instantiation: digest.c:lrmd_event_type2str
Unexecuted instantiation: health.c:lrmd_event_type2str
Unexecuted instantiation: io.c:lrmd_event_type2str
Unexecuted instantiation: ipc_client.c:lrmd_event_type2str
Unexecuted instantiation: ipc_common.c:lrmd_event_type2str
Unexecuted instantiation: ipc_controld.c:lrmd_event_type2str
Unexecuted instantiation: ipc_pacemakerd.c:lrmd_event_type2str
Unexecuted instantiation: ipc_schedulerd.c:lrmd_event_type2str
Unexecuted instantiation: ipc_server.c:lrmd_event_type2str
Unexecuted instantiation: messages.c:lrmd_event_type2str
Unexecuted instantiation: nodes.c:lrmd_event_type2str
Unexecuted instantiation: nvpair.c:lrmd_event_type2str
Unexecuted instantiation: options_display.c:lrmd_event_type2str
Unexecuted instantiation: patchset.c:lrmd_event_type2str
Unexecuted instantiation: procfs.c:lrmd_event_type2str
Unexecuted instantiation: rules.c:lrmd_event_type2str
Unexecuted instantiation: servers.c:lrmd_event_type2str
Unexecuted instantiation: cib.c:lrmd_event_type2str
Unexecuted instantiation: ipc_attrd.c:lrmd_event_type2str
Unexecuted instantiation: pid.c:lrmd_event_type2str
Unexecuted instantiation: attrs.c:lrmd_event_type2str
Unexecuted instantiation: strings_fuzzer.c:lrmd_event_type2str
Unexecuted instantiation: cib_file_fuzzer.c:lrmd_event_type2str
Unexecuted instantiation: cib_client.c:lrmd_event_type2str
Unexecuted instantiation: cib_file.c:lrmd_event_type2str
Unexecuted instantiation: cib_native.c:lrmd_event_type2str
Unexecuted instantiation: cib_ops.c:lrmd_event_type2str
Unexecuted instantiation: cib_remote.c:lrmd_event_type2str
Unexecuted instantiation: cib_utils.c:lrmd_event_type2str
Unexecuted instantiation: remote.c:lrmd_event_type2str
Unexecuted instantiation: tls.c:lrmd_event_type2str
Unexecuted instantiation: watchdog.c:lrmd_event_type2str
502
503
#ifdef __cplusplus
504
}
505
#endif
506
507
#endif