# NAME

libslack(msg) - message module

# SYNOPSIS

        #include <slack/std.h>
        #include <slack/msg.h>

        typedef struct Msg Msg;
        typedef void msg_out_t(void *data, const void *mesg, size_t mesglen);
        typedef int msg_filter_t(void **mesgp, const void *mesg, size_t mesglen);
        typedef void msg_release_t(void *data);

        Msg *msg_create(int type, msg_out_t *out, void *data, msg_release_t *destroy);
        Msg *msg_create_with_locker(Locker *locker, int type, msg_out_t *out, void *data, msg_release_t *destroy);
        int msg_rdlock(Msg *mesg);
        int msg_wrlock(Msg *mesg);
        int msg_unlock(Msg *mesg);
        void msg_release(Msg *mesg);
        void *msg_destroy(Msg **mesg);
        void msg_out(Msg *dst, const char *format, ...);
        void msg_out_unlocked(Msg *dst, const char *format, ...);
        void vmsg_out(Msg *dst, const char *format, va_list args);
        void vmsg_out_unlocked(Msg *dst, const char *format, va_list args);
        Msg *msg_create_fd(int fd);
        Msg *msg_create_fd_with_locker(Locker *locker, int fd);
        Msg *msg_create_stderr(void);
        Msg *msg_create_stderr_with_locker(Locker *locker);
        Msg *msg_create_stdout(void);
        Msg *msg_create_stdout_with_locker(Locker *locker);
        Msg *msg_create_file(const char *path);
        Msg *msg_create_file_with_locker(Locker *locker, const char *path);
        Msg *msg_create_syslog(const char *ident, int option, int facility, int priority);
        Msg *msg_create_syslog_with_locker(Locker *locker, const char *ident, int option, int facility, int priority);
        Msg *msg_syslog_set_facility(Msg *mesg, int facility);
        Msg *msg_syslog_set_facility_unlocked(Msg *mesg, int facility);
        Msg *msg_syslog_set_priority(Msg *mesg, int priority);
        Msg *msg_syslog_set_priority_unlocked(Msg *mesg, int priority);
        Msg *msg_create_plex(Msg *msg1, Msg *msg2);
        Msg *msg_create_plex_with_locker(Locker *locker, Msg *msg1, Msg *msg2);
        int msg_add_plex(Msg *mesg, Msg *item);
        int msg_add_plex_unlocked(Msg *mesg, Msg *item);
        Msg *msg_create_filter(msg_filter_t *filter, Msg *mesg);
        Msg *msg_create_filter_with_locker(Locker *locker, msg_filter_t *filter, Msg *mesg);
        const char *msg_set_timestamp_format(const char *format);
        int msg_set_timestamp_format_locker(Locker *locker);
        int syslog_lookup_facility(const char *facility);
        int syslog_lookup_priority(const char *priority);
        const char *syslog_facility_str(int spec);
        const char *syslog_priority_str(int spec);
        int syslog_parse(const char *spec, int *facility, int *priority);

# DESCRIPTION

This module provides general messaging functions. Message channels can be created that send messages to a file descriptor, a file, syslog or a client defined message handler or that multiplexes messages to any combination of the above. Messages sent to files are timestamped using (by default) the strftime(3) format: `"%Y%m%d %H:%M:%S"`.

It also provides functions for parsing syslog targets, converting between syslog facility names and codes, and converting between syslog priority names and codes.

`Msg *msg_create(int type, msg_out_t *out, void *data, msg_release_t *destroy)`

  Creates a Msg object initialised with `type`, `out`, `data` and `destroy`. Client-defined message handlers must specify a `type` greater than `5`. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy. It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null`.

`Msg *msg_create_with_locker(Locker *locker, int type, msg_out_t *out, void *data, msg_release_t *destroy)`

  Equivalent to msg_create(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`int msg_rdlock(Msg *mesg)`

  Claims a read lock on `mesg` (if `mesg` was created with a Locker). This is needed when multiple read-only msg(3) module functions need to be called atomically. It is the caller's responsibility to call msg_unlock(3) after the atomic operation. The only functions that may be called on `mesg` between calls to msg_rdlock(3) and msg_unlock(3) are any read-only msg(3) module functions whose name ends with `_unlocked`. On success, returns `0`. On error, returns an error code.

`int msg_wrlock(Msg *mesg)`

  Claims a write lock on `mesg`.

  Claims a write lock on `mesg` (if `mesg` was created with a Locker). This is needed when multiple read/write msg(3) module functions need to be called atomically. It is the caller's responsibility to call msg_unlock(3) after the atomic operation. The only functions that may be called on `mesg` between calls to msg_rdlock(3) and msg_unlock(3) are any msg(3) module functions whose name ends with `_unlocked`. On success, returns `0`. On error, returns an error code.

`int msg_unlock(Msg *mesg)`

  Unlocks a read or write lock on `mesg` obtained with msg_rdlock(3) or msg_wrlock(3) (if `mesg` was created with a Locker). On success, returns `0`. On error, returns an error code.

`void msg_release(Msg *mesg)`

  Releases (deallocates) `mesg` and its internal data.

`void *msg_destroy(Msg **mesg)`

  Destroys (deallocates and sets to `null`) `*mesg`. Returns `null`.

`void msg_out(Msg *dst, const char *format, ...)`

  Sends a message to `dst`. `format` is a printf(3)-like format string. Any remaining arguments are processed as in printf(3).

  Warning: Do not under any circumstances ever pass a non-literal string as the format argument unless you know exactly how many conversions will take place. Being careless with this is a very good way to build potential security vulnerabilities into your programs. The same is true for all functions that take a printf()-like format string as an argument.

          msg_out(dst, buf);       // EVIL
          msg_out(dst, "%s", buf); // GOOD

`void msg_out_unlocked(Msg *dst, const char *format, ...)`

  Equivalent to msg_out(3) except that `dst` is not read-locked.

`void vmsg_out(Msg *dst, const char *format, va_list args)`

  Sends a message to `dst`. `format` is a printf(3)-like format string. `args` is processed as in vprintf(3).

`void vmsg_out_unlocked(Msg *dst, const char *format, va_list args)`

  Equivalent to vmsg_out(3) except that `dst` is not read-locked.

`Msg *msg_create_fd(int fd)`

  Creates a Msg object that sends messages to file descriptor `fd`. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). On success, returns the new Msg object. On error, returns `null`.

`Msg *msg_create_fd_with_locker(Locker *locker, int fd)`

  Equivalent to msg_create_fd(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`Msg *msg_create_stderr(void)`

  Creates a Msg object that sends messages to standard error. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null`.

`Msg *msg_create_stderr_with_locker(Locker *locker)`

  Equivalent to msg_create_stderr(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`Msg *msg_create_stdout(void)`

  Creates a Msg object that sends messages to standard output. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null`.

`Msg *msg_create_stdout_with_locker(Locker *locker)`

  Equivalent to msg_create_stdout(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`Msg *msg_create_file(const char *path)`

  Creates a Msg object that sends messages to the file specified by `path`. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null` with `errno` set appropriately.

`Msg *msg_create_file_with_locker(Locker *locker, const char *path)`

  Equivalent to msg_create_file(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`Msg *msg_create_syslog(const char *ident, int option, int facility, int priority)`

  Creates a Msg object that sends messages to syslog initialised with `ident`, `option`, `facility` and `priority`. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null` with `errno` set appropriately.

`Msg *msg_create_syslog_with_locker(Locker *locker, const char *ident, int option, int facility, int priority)`

  Equivalent to msg_create_syslog(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`Msg *msg_syslog_set_facility(Msg *mesg, int facility)`

  Sets the facility field in `mesg`'s data to `facility`. On success, returns `mesg`. On error, returns `null` with `errno` set appropriately.

`Msg *msg_syslog_set_facility_unlocked(Msg *mesg, int facility)`

  Equivalent to msg_syslog_set_facility(3) except that `mesg` is not write-locked.

`Msg *msg_syslog_set_priority(Msg *mesg, int priority)`

  Sets the priority field in `mesg`'s data to `priority`. On success, returns `mesg`. On error, returns `null` with `errno` set appropriately.

`Msg *msg_syslog_set_priority_unlocked(Msg *mesg, int priority)`

  Equivalent to msg_syslog_set_priority(3) except that `mesg` is not write-locked.

`Msg *msg_create_plex(Msg *msg1, Msg *msg2)`

  Creates a Msg object that multiplexes messages to `msg1` and `msg2`. Further Msg objects may be added to its list using msg_add_plex(3). It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null` with `errno` set appropriately.

`Msg *msg_create_plex_with_locker(Locker *locker, Msg *msg1, Msg *msg2)`

  Equivalent to msg_create_plex(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`int msg_add_plex(Msg *mesg, Msg *item)`

  Adds `item` to the list of Msg objects multiplexed by `mesg`. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`int msg_add_plex_unlocked(Msg *mesg, Msg *item)`

  Equivalent to msg_add_plex(3) except that `mesg` is not write-locked.

`Msg *msg_create_filter(msg_filter_t *filter, Msg *mesg)`

  Creates a Msg object that sends messages to mesg after filtering messages through the filter function which must dynamically create a modified version of its input message which will be deallocated by its caller. It is the caller's responsibility to deallocate the new Msg with msg_release(3) or msg_destroy(3). It is strongly recommended to use msg_destroy(3), because it also sets the pointer variable to `null`. On success, returns the new Msg object. On error, returns `null` with `errno` set appropriately.

`Msg *msg_create_filter_with_locker(Locker *locker, msg_filter_t *filter, Msg *mesg)`

  Equivalent to msg_create_filter(3) except that multiple threads accessing the new Msg will be synchronised by `locker`.

`const char *msg_set_timestamp_format(const char *format)`

  Sets the strftime(3) format string used when sending messages to a file. By default, it is `"%Y%m%d %H:%M:%S "`. On success, returns the previous format string. On error, returns `null` with `errno` set appropriately.

`int msg_set_timestamp_format_locker(Locker *locker)`

  Sets the locking strategy for changing the timestamp format used when sending messages to a file. This is only needed if the timestamp format will be modified in multiple threads. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`int syslog_lookup_facility(const char *facility)`

  Returns the code corresponding to `facility`. If not found, returns `-1`.

`int syslog_lookup_priority(const char *priority)`

  Returns the code corresponding to `priority`. If not found, returns `-1`.

`const char *syslog_facility_str(int spec)`

  Returns the name corresponding to the facility part of `spec`. If not found, returns `null`.

`const char *syslog_priority_str(int spec)`

  Returns the name corresponding to the priority part of `spec`. If not found, returns `null`.

`int syslog_parse(const char *spec, int *facility, int *priority)`

  Parses `spec` as a facility.priority string. If `facility` is non-`null`, the parsed facility is stored in the location pointed to by `facility`. If `priority` is non-`null` the parsed priority is stored in the location pointed to by `priority`. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

  These are the supported syslog facility and priority names and their corresponding symbolic constants:

          syslog facilities          syslog priorities
          ----------------------     -----------------------
          "kern"      LOG_KERN       "emerg"       LOG_EMERG
          "user"      LOG_USER       "alert"       LOG_ALERT
          "mail"      LOG_MAIL       "crit"        LOG_CRIT
          "daemon"    LOG_DAEMON     "err"         LOG_ERR
          "auth"      LOG_AUTH       "warning"     LOG_WARNING
          "syslog"    LOG_SYSLOG     "info"        LOG_INFO
          "lpr"       LOG_LPR        "debug"       LOG_DEBUG
          "news"      LOG_NEWS
          "uucp"      LOG_UUCP
          "cron"      LOG_CRON
          "local0"    LOG_LOCAL0
          "local1"    LOG_LOCAL1
          "local2"    LOG_LOCAL2
          "local3"    LOG_LOCAL3
          "local4"    LOG_LOCAL4
          "local5"    LOG_LOCAL5
          "local6"    LOG_LOCAL6
          "local7"    LOG_LOCAL7

# ERRORS

On error, `errno` is set by underlying functions or as follows:

`EINVAL`

  An argument was `null`, or could not be parsed.

# MT-Level

MT-Disciplined - msg functions - See locker(3) for details.

MT-Safe - syslog functions

# EXAMPLE

Parse syslog facility priority pair:

        #include <slack/std.h>
        #include <slack/msg.h>

        int main(int ac, char **av)
        {
            int facility, priority;

            if (syslog_parse(av[1], &facility, &priority) != -1)
                syslog(facility | priority, "syslog(%s)", av[1]);

            return EXIT_SUCCESS;
        }

Multiplex a message to several locations:

        #include <slack/std.h>
        #include <slack/msg.h>

        int main(int ac, char **av)
        {
            Msg *stdout_msg = msg_create_stdout();
            Msg *stderr_msg = msg_create_stderr();
            Msg *file_msg = msg_create_file("/tmp/junk");
            Msg *syslog_msg = msg_create_syslog("ident", 0, LOG_DAEMON, LOG_ERR);
            Msg *plex_msg = msg_create_plex(stdout_msg, stderr_msg);

            msg_add_plex(plex_msg, file_msg);
            msg_add_plex(plex_msg, syslog_msg);

            msg_out(plex_msg, "Multiplex message\n");
            unlink("/tmp/junk");

            return EXIT_SUCCESS;
        }

# SEE ALSO

libslack(3), err(3), prog(3), openlog(3), syslog(3), locker(3)

# AUTHOR

20210220 raf <raf@raf.org>