13723Saf /*
23723Saf * CDDL HEADER START
33723Saf *
43723Saf * The contents of this file are subject to the terms of the
53723Saf * Common Development and Distribution License (the "License").
63723Saf * You may not use this file except in compliance with the License.
73723Saf *
83723Saf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93723Saf * or http://www.opensolaris.org/os/licensing.
103723Saf * See the License for the specific language governing permissions
113723Saf * and limitations under the License.
123723Saf *
133723Saf * When distributing Covered Code, include this CDDL HEADER in each
143723Saf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153723Saf * If applicable, add the following below this CDDL HEADER, with the
163723Saf * fields enclosed by brackets "[]" replaced with your own identifying
173723Saf * information: Portions Copyright [yyyy] [name of copyright owner]
183723Saf *
193723Saf * CDDL HEADER END
203723Saf */
219501SRobert.Johnston@Sun.COM
223723Saf /*
2312967Sgavin.maltby@oracle.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
243723Saf */
253723Saf
269501SRobert.Johnston@Sun.COM /*
279501SRobert.Johnston@Sun.COM * FMD Message Library
289501SRobert.Johnston@Sun.COM *
299501SRobert.Johnston@Sun.COM * This library supports a simple set of routines for use in converting FMA
309501SRobert.Johnston@Sun.COM * events and message codes to localized human-readable message strings.
319501SRobert.Johnston@Sun.COM *
329501SRobert.Johnston@Sun.COM * 1. Library API
339501SRobert.Johnston@Sun.COM *
349501SRobert.Johnston@Sun.COM * The APIs are as follows:
359501SRobert.Johnston@Sun.COM *
369501SRobert.Johnston@Sun.COM * fmd_msg_init - set up the library and return a handle
379501SRobert.Johnston@Sun.COM * fmd_msg_fini - destroy the handle from fmd_msg_init
389501SRobert.Johnston@Sun.COM *
399501SRobert.Johnston@Sun.COM * fmd_msg_locale_set - set the default locale (initially based on environ(5))
409501SRobert.Johnston@Sun.COM * fmd_msg_locale_get - get the default locale
419501SRobert.Johnston@Sun.COM *
429501SRobert.Johnston@Sun.COM * fmd_msg_url_set - set the default URL for knowledge articles
439501SRobert.Johnston@Sun.COM * fmd_msg_url_get - get the default URL for knowledge articles
449501SRobert.Johnston@Sun.COM *
459501SRobert.Johnston@Sun.COM * fmd_msg_gettext_nv - format the entire message for the given event
469501SRobert.Johnston@Sun.COM * fmd_msg_gettext_id - format the entire message for the given event code
4712967Sgavin.maltby@oracle.com * fmd_msg_gettext_key - format the entire message for the given dict for the
4812967Sgavin.maltby@oracle.com * given explicit message key
499501SRobert.Johnston@Sun.COM *
509501SRobert.Johnston@Sun.COM * fmd_msg_getitem_nv - format a single message item for the given event
519501SRobert.Johnston@Sun.COM * fmd_msg_getitem_id - format a single message item for the given event code
529501SRobert.Johnston@Sun.COM *
539501SRobert.Johnston@Sun.COM * Upon success, fmd_msg_gettext_* and fmd_msg_getitem_* return newly-allocated
549501SRobert.Johnston@Sun.COM * localized strings in multi-byte format. The caller must call free() on the
559501SRobert.Johnston@Sun.COM * resulting buffer to deallocate the string after making use of it. Upon
569501SRobert.Johnston@Sun.COM * failure, these functions return NULL and set errno as follows:
579501SRobert.Johnston@Sun.COM *
589501SRobert.Johnston@Sun.COM * ENOMEM - Memory allocation failure while formatting message
599501SRobert.Johnston@Sun.COM * ENOENT - No message was found for the specified message identifier
609501SRobert.Johnston@Sun.COM * EINVAL - Invalid argument (e.g. bad event code, illegal fmd_msg_item_t)
619501SRobert.Johnston@Sun.COM * EILSEQ - Illegal multi-byte sequence detected in message
629501SRobert.Johnston@Sun.COM *
639501SRobert.Johnston@Sun.COM * 2. Variable Expansion
649501SRobert.Johnston@Sun.COM *
659501SRobert.Johnston@Sun.COM * The human-readable messages are stored in msgfmt(1) message object files in
669501SRobert.Johnston@Sun.COM * the corresponding locale directories. The values for the message items are
679501SRobert.Johnston@Sun.COM * permitted to contain variable expansions, currently defined as follows:
689501SRobert.Johnston@Sun.COM *
699501SRobert.Johnston@Sun.COM * %% - literal % character
709501SRobert.Johnston@Sun.COM * %s - knowledge article URL (e.g. http://sun.com/msg/<MSG-ID>)
719501SRobert.Johnston@Sun.COM * %< x > - value x from the current event, using the expression syntax below:
729501SRobert.Johnston@Sun.COM *
739501SRobert.Johnston@Sun.COM * foo.bar => print nvlist_t member "bar" contained within nvlist_t "foo"
749501SRobert.Johnston@Sun.COM * foo[123] => print array element 123 of nvlist_t member "foo"
759501SRobert.Johnston@Sun.COM * foo[123].bar => print member "bar" of nvlist_t element 123 in array "foo"
769501SRobert.Johnston@Sun.COM *
779501SRobert.Johnston@Sun.COM * For example, the msgstr value for FMD-8000-2K might be defined as:
789501SRobert.Johnston@Sun.COM *
799501SRobert.Johnston@Sun.COM * msgid "FMD-8000-2K.action"
809501SRobert.Johnston@Sun.COM * msgstr "Use fmdump -v -u %<uuid> to locate the module. Use fmadm \
819501SRobert.Johnston@Sun.COM * reset %<fault-list[0].asru.mod-name> to reset the module."
829501SRobert.Johnston@Sun.COM *
839501SRobert.Johnston@Sun.COM * 3. Locking
849501SRobert.Johnston@Sun.COM *
859501SRobert.Johnston@Sun.COM * In order to format a human-readable message, libfmd_msg must get and set
869501SRobert.Johnston@Sun.COM * the process locale and potentially alter text domain bindings. At present,
879501SRobert.Johnston@Sun.COM * these facilities in libc are not fully MT-safe. As such, a library-wide
889501SRobert.Johnston@Sun.COM * lock is provided: fmd_msg_lock() and fmd_msg_unlock(). These locking calls
899501SRobert.Johnston@Sun.COM * are made internally as part of the top-level library entry points, but they
909501SRobert.Johnston@Sun.COM * can also be used by applications that themselves call setlocale() and wish
919501SRobert.Johnston@Sun.COM * to appropriately synchronize with other threads that are calling libfmd_msg.
929501SRobert.Johnston@Sun.COM */
933723Saf
949501SRobert.Johnston@Sun.COM
959501SRobert.Johnston@Sun.COM #include <sys/fm/protocol.h>
969501SRobert.Johnston@Sun.COM
979501SRobert.Johnston@Sun.COM #include <libintl.h>
989501SRobert.Johnston@Sun.COM #include <locale.h>
999501SRobert.Johnston@Sun.COM #include <wchar.h>
1009501SRobert.Johnston@Sun.COM
1019501SRobert.Johnston@Sun.COM #include <alloca.h>
1029501SRobert.Johnston@Sun.COM #include <assert.h>
10312967Sgavin.maltby@oracle.com #include <netdb.h>
1049501SRobert.Johnston@Sun.COM #include <pthread.h>
10511466SRoger.Faulkner@Sun.COM #include <synch.h>
1069501SRobert.Johnston@Sun.COM #include <strings.h>
1079501SRobert.Johnston@Sun.COM #include <stdarg.h>
1083723Saf #include <stdlib.h>
1099501SRobert.Johnston@Sun.COM #include <stdio.h>
1109501SRobert.Johnston@Sun.COM #include <errno.h>
11112967Sgavin.maltby@oracle.com #include <unistd.h>
1129501SRobert.Johnston@Sun.COM #include <sys/sysmacros.h>
1139501SRobert.Johnston@Sun.COM
1149501SRobert.Johnston@Sun.COM #include <fmd_msg.h>
1159501SRobert.Johnston@Sun.COM
1169501SRobert.Johnston@Sun.COM #define FMD_MSGBUF_SZ 256
1179501SRobert.Johnston@Sun.COM
1189501SRobert.Johnston@Sun.COM struct fmd_msg_hdl {
1199501SRobert.Johnston@Sun.COM int fmh_version; /* libfmd_msg client abi version number */
1209501SRobert.Johnston@Sun.COM char *fmh_urlbase; /* base url for all knowledge articles */
1219501SRobert.Johnston@Sun.COM char *fmh_binding; /* base directory for bindtextdomain() */
1229501SRobert.Johnston@Sun.COM char *fmh_locale; /* default program locale from environment */
1239501SRobert.Johnston@Sun.COM const char *fmh_template; /* FMD_MSG_TEMPLATE value for fmh_locale */
1249501SRobert.Johnston@Sun.COM };
1253723Saf
1269501SRobert.Johnston@Sun.COM typedef struct fmd_msg_buf {
1279501SRobert.Johnston@Sun.COM wchar_t *fmb_data; /* wide-character data buffer */
1289501SRobert.Johnston@Sun.COM size_t fmb_size; /* size of fmb_data in wchar_t units */
1299501SRobert.Johnston@Sun.COM size_t fmb_used; /* used portion of fmb_data in wchar_t units */
1309501SRobert.Johnston@Sun.COM int fmb_error; /* error if any has occurred */
1319501SRobert.Johnston@Sun.COM } fmd_msg_buf_t;
1329501SRobert.Johnston@Sun.COM
1339501SRobert.Johnston@Sun.COM static const char *const fmd_msg_items[] = {
1349501SRobert.Johnston@Sun.COM "type", /* key for FMD_MSG_ITEM_TYPE */
1359501SRobert.Johnston@Sun.COM "severity", /* key for FMD_MSG_ITEM_SEVERITY */
1369501SRobert.Johnston@Sun.COM "description", /* key for FMD_MSG_ITEM_DESC */
1379501SRobert.Johnston@Sun.COM "response", /* key for FMD_MSG_ITEM_RESPONSE */
1389501SRobert.Johnston@Sun.COM "impact", /* key for FMD_MSG_ITEM_IMPACT */
1399501SRobert.Johnston@Sun.COM "action", /* key for FMD_MSG_ITEM_ACTION */
1409501SRobert.Johnston@Sun.COM "url", /* key for FMD_MSG_ITEM_URL */
1419501SRobert.Johnston@Sun.COM };
1423723Saf
1439501SRobert.Johnston@Sun.COM static pthread_rwlock_t fmd_msg_rwlock = PTHREAD_RWLOCK_INITIALIZER;
1449501SRobert.Johnston@Sun.COM
1459501SRobert.Johnston@Sun.COM static const char FMD_MSG_DOMAIN[] = "FMD";
1469501SRobert.Johnston@Sun.COM static const char FMD_MSG_TEMPLATE[] = "syslog-msgs-message-template";
1479501SRobert.Johnston@Sun.COM static const char FMD_MSG_URLKEY[] = "syslog-url";
1489501SRobert.Johnston@Sun.COM static const char FMD_MSG_URLBASE[] = "http://sun.com/msg/";
1499501SRobert.Johnston@Sun.COM static const char FMD_MSG_NLSPATH[] = "NLSPATH=/usr/lib/fm/fmd/fmd.cat";
1509501SRobert.Johnston@Sun.COM static const char FMD_MSG_MISSING[] = "-";
1519501SRobert.Johnston@Sun.COM
1529501SRobert.Johnston@Sun.COM /*
1539501SRobert.Johnston@Sun.COM * An enumeration of token types. The following are valid tokens that can be
1549501SRobert.Johnston@Sun.COM * embedded into the message content:
1559501SRobert.Johnston@Sun.COM *
1569501SRobert.Johnston@Sun.COM * T_INT - integer tokens (for array indices)
1579501SRobert.Johnston@Sun.COM * T_IDENT - nvpair identifiers
1589501SRobert.Johnston@Sun.COM * T_DOT - "."
1599501SRobert.Johnston@Sun.COM * T_LBRAC - "["
1609501SRobert.Johnston@Sun.COM * T_RBRAC - "]"
1619501SRobert.Johnston@Sun.COM *
1629501SRobert.Johnston@Sun.COM * A NULL character (T_EOF) is used to terminate messages.
1639501SRobert.Johnston@Sun.COM * Invalid tokens are assigned the type T_ERR.
1649501SRobert.Johnston@Sun.COM */
1659501SRobert.Johnston@Sun.COM typedef enum {
1669501SRobert.Johnston@Sun.COM T_EOF,
1679501SRobert.Johnston@Sun.COM T_ERR,
1689501SRobert.Johnston@Sun.COM T_IDENT,
1699501SRobert.Johnston@Sun.COM T_INT,
1709501SRobert.Johnston@Sun.COM T_DOT,
1719501SRobert.Johnston@Sun.COM T_LBRAC,
1729501SRobert.Johnston@Sun.COM T_RBRAC
1739501SRobert.Johnston@Sun.COM } fmd_msg_nv_tkind_t;
1749501SRobert.Johnston@Sun.COM
1759501SRobert.Johnston@Sun.COM typedef struct fmd_msg_nv_token {
1769501SRobert.Johnston@Sun.COM fmd_msg_nv_tkind_t t_kind;
1779501SRobert.Johnston@Sun.COM union {
1789501SRobert.Johnston@Sun.COM char tu_str[256];
1799501SRobert.Johnston@Sun.COM uint_t tu_int;
1809501SRobert.Johnston@Sun.COM } t_data;
1819501SRobert.Johnston@Sun.COM } fmd_msg_nv_token_t;
1829501SRobert.Johnston@Sun.COM
1839501SRobert.Johnston@Sun.COM static const struct fmd_msg_nv_type {
1849501SRobert.Johnston@Sun.COM data_type_t nvt_type;
1859501SRobert.Johnston@Sun.COM data_type_t nvt_base;
1869501SRobert.Johnston@Sun.COM size_t nvt_size;
1879501SRobert.Johnston@Sun.COM int (*nvt_value)();
1889501SRobert.Johnston@Sun.COM int (*nvt_array)();
1899501SRobert.Johnston@Sun.COM } fmd_msg_nv_types[] = {
1909501SRobert.Johnston@Sun.COM { DATA_TYPE_INT8, DATA_TYPE_INT8,
1919501SRobert.Johnston@Sun.COM sizeof (int8_t), nvpair_value_int8, NULL },
1929501SRobert.Johnston@Sun.COM { DATA_TYPE_INT16, DATA_TYPE_INT16,
1939501SRobert.Johnston@Sun.COM sizeof (int16_t), nvpair_value_int16, NULL },
1949501SRobert.Johnston@Sun.COM { DATA_TYPE_INT32, DATA_TYPE_INT32,
1959501SRobert.Johnston@Sun.COM sizeof (int32_t), nvpair_value_int32, NULL },
1969501SRobert.Johnston@Sun.COM { DATA_TYPE_INT64, DATA_TYPE_INT64,
1979501SRobert.Johnston@Sun.COM sizeof (int64_t), nvpair_value_int64, NULL },
1989501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT8, DATA_TYPE_UINT8,
1999501SRobert.Johnston@Sun.COM sizeof (uint8_t), nvpair_value_uint8, NULL },
2009501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT16, DATA_TYPE_UINT16,
2019501SRobert.Johnston@Sun.COM sizeof (uint16_t), nvpair_value_uint16, NULL },
2029501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT32, DATA_TYPE_UINT32,
2039501SRobert.Johnston@Sun.COM sizeof (uint32_t), nvpair_value_uint32, NULL },
2049501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT64, DATA_TYPE_UINT64,
2059501SRobert.Johnston@Sun.COM sizeof (uint64_t), nvpair_value_uint64, NULL },
2069501SRobert.Johnston@Sun.COM { DATA_TYPE_BYTE, DATA_TYPE_BYTE,
2079501SRobert.Johnston@Sun.COM sizeof (uchar_t), nvpair_value_byte, NULL },
2089501SRobert.Johnston@Sun.COM { DATA_TYPE_BOOLEAN, DATA_TYPE_BOOLEAN,
2099501SRobert.Johnston@Sun.COM 0, NULL, NULL },
2109501SRobert.Johnston@Sun.COM { DATA_TYPE_BOOLEAN_VALUE, DATA_TYPE_BOOLEAN_VALUE,
2119501SRobert.Johnston@Sun.COM sizeof (boolean_t), nvpair_value_boolean_value, NULL },
2129501SRobert.Johnston@Sun.COM { DATA_TYPE_HRTIME, DATA_TYPE_HRTIME,
2139501SRobert.Johnston@Sun.COM sizeof (hrtime_t), nvpair_value_hrtime, NULL },
2149501SRobert.Johnston@Sun.COM { DATA_TYPE_STRING, DATA_TYPE_STRING,
2159501SRobert.Johnston@Sun.COM sizeof (char *), nvpair_value_string, NULL },
2169501SRobert.Johnston@Sun.COM { DATA_TYPE_NVLIST, DATA_TYPE_NVLIST,
2179501SRobert.Johnston@Sun.COM sizeof (nvlist_t *), nvpair_value_nvlist, NULL },
2189501SRobert.Johnston@Sun.COM { DATA_TYPE_INT8_ARRAY, DATA_TYPE_INT8,
2199501SRobert.Johnston@Sun.COM sizeof (int8_t), NULL, nvpair_value_int8_array },
2209501SRobert.Johnston@Sun.COM { DATA_TYPE_INT16_ARRAY, DATA_TYPE_INT16,
2219501SRobert.Johnston@Sun.COM sizeof (int16_t), NULL, nvpair_value_int16_array },
2229501SRobert.Johnston@Sun.COM { DATA_TYPE_INT32_ARRAY, DATA_TYPE_INT32,
2239501SRobert.Johnston@Sun.COM sizeof (int32_t), NULL, nvpair_value_int32_array },
2249501SRobert.Johnston@Sun.COM { DATA_TYPE_INT64_ARRAY, DATA_TYPE_INT64,
2259501SRobert.Johnston@Sun.COM sizeof (int64_t), NULL, nvpair_value_int64_array },
2269501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT8_ARRAY, DATA_TYPE_UINT8,
2279501SRobert.Johnston@Sun.COM sizeof (uint8_t), NULL, nvpair_value_uint8_array },
2289501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT16_ARRAY, DATA_TYPE_UINT16,
2299501SRobert.Johnston@Sun.COM sizeof (uint16_t), NULL, nvpair_value_uint16_array },
2309501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT32_ARRAY, DATA_TYPE_UINT32,
2319501SRobert.Johnston@Sun.COM sizeof (uint32_t), NULL, nvpair_value_uint32_array },
2329501SRobert.Johnston@Sun.COM { DATA_TYPE_UINT64_ARRAY, DATA_TYPE_UINT64,
2339501SRobert.Johnston@Sun.COM sizeof (uint64_t), NULL, nvpair_value_uint64_array },
2349501SRobert.Johnston@Sun.COM { DATA_TYPE_BYTE_ARRAY, DATA_TYPE_BYTE,
2359501SRobert.Johnston@Sun.COM sizeof (uchar_t), NULL, nvpair_value_byte_array },
2369501SRobert.Johnston@Sun.COM { DATA_TYPE_BOOLEAN_ARRAY, DATA_TYPE_BOOLEAN_VALUE,
2379501SRobert.Johnston@Sun.COM sizeof (boolean_t), NULL, nvpair_value_boolean_array },
2389501SRobert.Johnston@Sun.COM { DATA_TYPE_STRING_ARRAY, DATA_TYPE_STRING,
2399501SRobert.Johnston@Sun.COM sizeof (char *), NULL, nvpair_value_string_array },
2409501SRobert.Johnston@Sun.COM { DATA_TYPE_NVLIST_ARRAY, DATA_TYPE_NVLIST,
2419501SRobert.Johnston@Sun.COM sizeof (nvlist_t *), NULL, nvpair_value_nvlist_array },
2429501SRobert.Johnston@Sun.COM { DATA_TYPE_UNKNOWN, DATA_TYPE_UNKNOWN, 0, NULL, NULL }
2439501SRobert.Johnston@Sun.COM };
2449501SRobert.Johnston@Sun.COM
2459501SRobert.Johnston@Sun.COM static int fmd_msg_nv_parse_nvpair(fmd_msg_buf_t *, nvpair_t *, char *);
2469501SRobert.Johnston@Sun.COM static int fmd_msg_nv_parse_nvname(fmd_msg_buf_t *, nvlist_t *, char *);
2479501SRobert.Johnston@Sun.COM static int fmd_msg_nv_parse_nvlist(fmd_msg_buf_t *, nvlist_t *, char *);
2489501SRobert.Johnston@Sun.COM
2499501SRobert.Johnston@Sun.COM /*ARGSUSED*/
2509501SRobert.Johnston@Sun.COM static int
fmd_msg_lock_held(fmd_msg_hdl_t * h)2519501SRobert.Johnston@Sun.COM fmd_msg_lock_held(fmd_msg_hdl_t *h)
2523723Saf {
25311466SRoger.Faulkner@Sun.COM return (RW_WRITE_HELD(&fmd_msg_rwlock));
2543723Saf }
2553723Saf
2563723Saf void
fmd_msg_lock(void)2573723Saf fmd_msg_lock(void)
2583723Saf {
2599501SRobert.Johnston@Sun.COM if (pthread_rwlock_wrlock(&fmd_msg_rwlock) != 0)
2603723Saf abort();
2613723Saf }
2623723Saf
2633723Saf void
fmd_msg_unlock(void)2643723Saf fmd_msg_unlock(void)
2653723Saf {
2669501SRobert.Johnston@Sun.COM if (pthread_rwlock_unlock(&fmd_msg_rwlock) != 0)
2673723Saf abort();
2683723Saf }
2699501SRobert.Johnston@Sun.COM
2709501SRobert.Johnston@Sun.COM static fmd_msg_hdl_t *
fmd_msg_init_err(fmd_msg_hdl_t * h,int err)2719501SRobert.Johnston@Sun.COM fmd_msg_init_err(fmd_msg_hdl_t *h, int err)
2729501SRobert.Johnston@Sun.COM {
2739501SRobert.Johnston@Sun.COM fmd_msg_fini(h);
2749501SRobert.Johnston@Sun.COM errno = err;
2759501SRobert.Johnston@Sun.COM return (NULL);
2769501SRobert.Johnston@Sun.COM }
2779501SRobert.Johnston@Sun.COM
2789501SRobert.Johnston@Sun.COM fmd_msg_hdl_t *
fmd_msg_init(const char * root,int version)2799501SRobert.Johnston@Sun.COM fmd_msg_init(const char *root, int version)
2809501SRobert.Johnston@Sun.COM {
2819501SRobert.Johnston@Sun.COM fmd_msg_hdl_t *h = NULL;
2829501SRobert.Johnston@Sun.COM const char *s;
2839501SRobert.Johnston@Sun.COM size_t len;
2849501SRobert.Johnston@Sun.COM
2859501SRobert.Johnston@Sun.COM if (version != FMD_MSG_VERSION)
2869501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, EINVAL));
2879501SRobert.Johnston@Sun.COM
2889501SRobert.Johnston@Sun.COM if ((h = malloc(sizeof (fmd_msg_hdl_t))) == NULL)
2899501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, ENOMEM));
2909501SRobert.Johnston@Sun.COM
2919501SRobert.Johnston@Sun.COM bzero(h, sizeof (fmd_msg_hdl_t));
2929501SRobert.Johnston@Sun.COM h->fmh_version = version;
2939501SRobert.Johnston@Sun.COM
2949501SRobert.Johnston@Sun.COM if ((h->fmh_urlbase = strdup(FMD_MSG_URLBASE)) == NULL)
2959501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, ENOMEM));
2969501SRobert.Johnston@Sun.COM
2979501SRobert.Johnston@Sun.COM /*
2989501SRobert.Johnston@Sun.COM * Initialize the program's locale from the environment if it hasn't
2999501SRobert.Johnston@Sun.COM * already been initialized, and then retrieve the default setting.
3009501SRobert.Johnston@Sun.COM */
3019501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, "");
3029501SRobert.Johnston@Sun.COM s = setlocale(LC_ALL, NULL);
3039501SRobert.Johnston@Sun.COM h->fmh_locale = strdup(s ? s : "C");
3049501SRobert.Johnston@Sun.COM
3059501SRobert.Johnston@Sun.COM if (h->fmh_locale == NULL)
3069501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, ENOMEM));
3079501SRobert.Johnston@Sun.COM
3089501SRobert.Johnston@Sun.COM /*
3099501SRobert.Johnston@Sun.COM * If a non-default root directory is specified, then look up the base
3109501SRobert.Johnston@Sun.COM * directory for our default catalog, and set fmh_binding as the same
3119501SRobert.Johnston@Sun.COM * directory prefixed with the new root directory. This simply turns
3129501SRobert.Johnston@Sun.COM * usr/lib/locale into <rootdir>/usr/lib/locale, but handles all of the
3139501SRobert.Johnston@Sun.COM * environ(5) settings that can change the default messages binding.
3149501SRobert.Johnston@Sun.COM */
3159501SRobert.Johnston@Sun.COM if (root != NULL && root[0] != '\0' && strcmp(root, "/") != 0) {
3169501SRobert.Johnston@Sun.COM if (root[0] != '/')
3179501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, EINVAL));
3189501SRobert.Johnston@Sun.COM
3199501SRobert.Johnston@Sun.COM if ((s = bindtextdomain(FMD_MSG_DOMAIN, NULL)) == NULL)
3209501SRobert.Johnston@Sun.COM s = "/usr/lib/locale"; /* substitute default */
3219501SRobert.Johnston@Sun.COM
3229501SRobert.Johnston@Sun.COM len = strlen(root) + strlen(s) + 1;
3239501SRobert.Johnston@Sun.COM
3249501SRobert.Johnston@Sun.COM if ((h->fmh_binding = malloc(len)) == NULL)
3259501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, ENOMEM));
3269501SRobert.Johnston@Sun.COM
3279501SRobert.Johnston@Sun.COM (void) snprintf(h->fmh_binding, len, "%s%s", root, s);
3289501SRobert.Johnston@Sun.COM }
3299501SRobert.Johnston@Sun.COM
3309501SRobert.Johnston@Sun.COM /*
3319501SRobert.Johnston@Sun.COM * All FMA event dictionaries use msgfmt(1) message objects to produce
3329501SRobert.Johnston@Sun.COM * messages, even for the C locale. We therefore want to use dgettext
3339501SRobert.Johnston@Sun.COM * for all message lookups, but its defined behavior in the C locale is
3349501SRobert.Johnston@Sun.COM * to return the input string. Since our input strings are event codes
3359501SRobert.Johnston@Sun.COM * and not format strings, this doesn't help us. We resolve this nit
3369501SRobert.Johnston@Sun.COM * by setting NLSPATH to a non-existent file: the presence of NLSPATH
3379501SRobert.Johnston@Sun.COM * is defined to force dgettext(3C) to do a full lookup even for C.
3389501SRobert.Johnston@Sun.COM */
3399501SRobert.Johnston@Sun.COM if (getenv("NLSPATH") == NULL &&
3409501SRobert.Johnston@Sun.COM ((s = strdup(FMD_MSG_NLSPATH)) == NULL || putenv((char *)s) != 0))
3419501SRobert.Johnston@Sun.COM return (fmd_msg_init_err(h, errno));
3429501SRobert.Johnston@Sun.COM
3439501SRobert.Johnston@Sun.COM /*
3449501SRobert.Johnston@Sun.COM * Cache the message template for the current locale. This is the
3459501SRobert.Johnston@Sun.COM * snprintf(3C) format string for the final human-readable message.
34611472SRobert.Johnston@Sun.COM * If the lookup fails for the current locale, fall back to the C locale
34711472SRobert.Johnston@Sun.COM * and try again. Then restore the original locale.
3489501SRobert.Johnston@Sun.COM */
34911472SRobert.Johnston@Sun.COM if ((h->fmh_template = dgettext(FMD_MSG_DOMAIN, FMD_MSG_TEMPLATE))
35011472SRobert.Johnston@Sun.COM == FMD_MSG_TEMPLATE && strcmp(h->fmh_locale, "C") != 0) {
35111472SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, "C");
35211472SRobert.Johnston@Sun.COM h->fmh_template = dgettext(FMD_MSG_DOMAIN, FMD_MSG_TEMPLATE);
35311472SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, h->fmh_locale);
35411472SRobert.Johnston@Sun.COM }
3559501SRobert.Johnston@Sun.COM
3569501SRobert.Johnston@Sun.COM return (h);
3579501SRobert.Johnston@Sun.COM }
3589501SRobert.Johnston@Sun.COM
3599501SRobert.Johnston@Sun.COM void
fmd_msg_fini(fmd_msg_hdl_t * h)3609501SRobert.Johnston@Sun.COM fmd_msg_fini(fmd_msg_hdl_t *h)
3619501SRobert.Johnston@Sun.COM {
3629501SRobert.Johnston@Sun.COM if (h == NULL)
3639501SRobert.Johnston@Sun.COM return; /* simplify caller code */
3649501SRobert.Johnston@Sun.COM
3659501SRobert.Johnston@Sun.COM free(h->fmh_binding);
3669501SRobert.Johnston@Sun.COM free(h->fmh_urlbase);
3679501SRobert.Johnston@Sun.COM free(h->fmh_locale);
3689501SRobert.Johnston@Sun.COM free(h);
3699501SRobert.Johnston@Sun.COM }
3709501SRobert.Johnston@Sun.COM
3719501SRobert.Johnston@Sun.COM int
fmd_msg_locale_set(fmd_msg_hdl_t * h,const char * locale)3729501SRobert.Johnston@Sun.COM fmd_msg_locale_set(fmd_msg_hdl_t *h, const char *locale)
3739501SRobert.Johnston@Sun.COM {
3749501SRobert.Johnston@Sun.COM char *l;
3759501SRobert.Johnston@Sun.COM
3769501SRobert.Johnston@Sun.COM if (locale == NULL) {
3779501SRobert.Johnston@Sun.COM errno = EINVAL;
3789501SRobert.Johnston@Sun.COM return (-1);
3799501SRobert.Johnston@Sun.COM }
3809501SRobert.Johnston@Sun.COM
3819501SRobert.Johnston@Sun.COM if ((l = strdup(locale)) == NULL) {
3829501SRobert.Johnston@Sun.COM errno = ENOMEM;
3839501SRobert.Johnston@Sun.COM return (-1);
3849501SRobert.Johnston@Sun.COM }
3859501SRobert.Johnston@Sun.COM
3869501SRobert.Johnston@Sun.COM fmd_msg_lock();
3879501SRobert.Johnston@Sun.COM
3889501SRobert.Johnston@Sun.COM if (setlocale(LC_ALL, l) == NULL) {
3899501SRobert.Johnston@Sun.COM free(l);
3909501SRobert.Johnston@Sun.COM errno = EINVAL;
3919501SRobert.Johnston@Sun.COM fmd_msg_unlock();
3929501SRobert.Johnston@Sun.COM return (-1);
3939501SRobert.Johnston@Sun.COM }
3949501SRobert.Johnston@Sun.COM
3959501SRobert.Johnston@Sun.COM h->fmh_template = dgettext(FMD_MSG_DOMAIN, FMD_MSG_TEMPLATE);
3969501SRobert.Johnston@Sun.COM free(h->fmh_locale);
3979501SRobert.Johnston@Sun.COM h->fmh_locale = l;
3989501SRobert.Johnston@Sun.COM
3999501SRobert.Johnston@Sun.COM fmd_msg_unlock();
4009501SRobert.Johnston@Sun.COM return (0);
4019501SRobert.Johnston@Sun.COM }
4029501SRobert.Johnston@Sun.COM
4039501SRobert.Johnston@Sun.COM const char *
fmd_msg_locale_get(fmd_msg_hdl_t * h)4049501SRobert.Johnston@Sun.COM fmd_msg_locale_get(fmd_msg_hdl_t *h)
4059501SRobert.Johnston@Sun.COM {
4069501SRobert.Johnston@Sun.COM return (h->fmh_locale);
4079501SRobert.Johnston@Sun.COM }
4089501SRobert.Johnston@Sun.COM
4099501SRobert.Johnston@Sun.COM int
fmd_msg_url_set(fmd_msg_hdl_t * h,const char * url)4109501SRobert.Johnston@Sun.COM fmd_msg_url_set(fmd_msg_hdl_t *h, const char *url)
4119501SRobert.Johnston@Sun.COM {
4129501SRobert.Johnston@Sun.COM char *u;
4139501SRobert.Johnston@Sun.COM
4149501SRobert.Johnston@Sun.COM if (url == NULL) {
4159501SRobert.Johnston@Sun.COM errno = EINVAL;
4169501SRobert.Johnston@Sun.COM return (-1);
4179501SRobert.Johnston@Sun.COM }
4189501SRobert.Johnston@Sun.COM
4199501SRobert.Johnston@Sun.COM if ((u = strdup(url)) == NULL) {
4209501SRobert.Johnston@Sun.COM errno = ENOMEM;
4219501SRobert.Johnston@Sun.COM return (-1);
4229501SRobert.Johnston@Sun.COM }
4239501SRobert.Johnston@Sun.COM
4249501SRobert.Johnston@Sun.COM fmd_msg_lock();
4259501SRobert.Johnston@Sun.COM
4269501SRobert.Johnston@Sun.COM free(h->fmh_urlbase);
4279501SRobert.Johnston@Sun.COM h->fmh_urlbase = u;
4289501SRobert.Johnston@Sun.COM
4299501SRobert.Johnston@Sun.COM fmd_msg_unlock();
4309501SRobert.Johnston@Sun.COM return (0);
4319501SRobert.Johnston@Sun.COM }
4329501SRobert.Johnston@Sun.COM
4339501SRobert.Johnston@Sun.COM const char *
fmd_msg_url_get(fmd_msg_hdl_t * h)4349501SRobert.Johnston@Sun.COM fmd_msg_url_get(fmd_msg_hdl_t *h)
4359501SRobert.Johnston@Sun.COM {
4369501SRobert.Johnston@Sun.COM return (h->fmh_urlbase);
4379501SRobert.Johnston@Sun.COM }
4389501SRobert.Johnston@Sun.COM
4399501SRobert.Johnston@Sun.COM static wchar_t *
fmd_msg_mbstowcs(const char * s)4409501SRobert.Johnston@Sun.COM fmd_msg_mbstowcs(const char *s)
4419501SRobert.Johnston@Sun.COM {
4429501SRobert.Johnston@Sun.COM size_t n = strlen(s) + 1;
4439501SRobert.Johnston@Sun.COM wchar_t *w = malloc(n * sizeof (wchar_t));
4449501SRobert.Johnston@Sun.COM
4459501SRobert.Johnston@Sun.COM if (w == NULL) {
4469501SRobert.Johnston@Sun.COM errno = ENOMEM;
4479501SRobert.Johnston@Sun.COM return (NULL);
4489501SRobert.Johnston@Sun.COM }
4499501SRobert.Johnston@Sun.COM
4509501SRobert.Johnston@Sun.COM if (mbstowcs(w, s, n) == (size_t)-1) {
4519501SRobert.Johnston@Sun.COM free(w);
4529501SRobert.Johnston@Sun.COM return (NULL);
4539501SRobert.Johnston@Sun.COM }
4549501SRobert.Johnston@Sun.COM
4559501SRobert.Johnston@Sun.COM return (w);
4569501SRobert.Johnston@Sun.COM }
4579501SRobert.Johnston@Sun.COM
4589501SRobert.Johnston@Sun.COM static void
fmd_msg_buf_init(fmd_msg_buf_t * b)4599501SRobert.Johnston@Sun.COM fmd_msg_buf_init(fmd_msg_buf_t *b)
4609501SRobert.Johnston@Sun.COM {
4619501SRobert.Johnston@Sun.COM bzero(b, sizeof (fmd_msg_buf_t));
4629501SRobert.Johnston@Sun.COM b->fmb_data = malloc(sizeof (wchar_t) * FMD_MSGBUF_SZ);
4639501SRobert.Johnston@Sun.COM
4649501SRobert.Johnston@Sun.COM if (b->fmb_data == NULL)
4659501SRobert.Johnston@Sun.COM b->fmb_error = ENOMEM;
4669501SRobert.Johnston@Sun.COM else
4679501SRobert.Johnston@Sun.COM b->fmb_size = FMD_MSGBUF_SZ;
4689501SRobert.Johnston@Sun.COM }
4699501SRobert.Johnston@Sun.COM
4709501SRobert.Johnston@Sun.COM static void
fmd_msg_buf_fini(fmd_msg_buf_t * b)4719501SRobert.Johnston@Sun.COM fmd_msg_buf_fini(fmd_msg_buf_t *b)
4729501SRobert.Johnston@Sun.COM {
4739501SRobert.Johnston@Sun.COM free(b->fmb_data);
4749501SRobert.Johnston@Sun.COM bzero(b, sizeof (fmd_msg_buf_t));
4759501SRobert.Johnston@Sun.COM }
4769501SRobert.Johnston@Sun.COM
4779501SRobert.Johnston@Sun.COM static char *
fmd_msg_buf_read(fmd_msg_buf_t * b)4789501SRobert.Johnston@Sun.COM fmd_msg_buf_read(fmd_msg_buf_t *b)
4799501SRobert.Johnston@Sun.COM {
4809501SRobert.Johnston@Sun.COM char *s;
4819501SRobert.Johnston@Sun.COM
4829501SRobert.Johnston@Sun.COM if (b->fmb_error != 0) {
4839501SRobert.Johnston@Sun.COM errno = b->fmb_error;
4849501SRobert.Johnston@Sun.COM return (NULL);
4859501SRobert.Johnston@Sun.COM }
4869501SRobert.Johnston@Sun.COM
4879501SRobert.Johnston@Sun.COM if ((s = malloc(b->fmb_used * MB_CUR_MAX)) == NULL) {
4889501SRobert.Johnston@Sun.COM errno = ENOMEM;
4899501SRobert.Johnston@Sun.COM return (NULL);
4909501SRobert.Johnston@Sun.COM }
4919501SRobert.Johnston@Sun.COM
4929501SRobert.Johnston@Sun.COM if (wcstombs(s, b->fmb_data, b->fmb_used) == (size_t)-1) {
4939501SRobert.Johnston@Sun.COM free(s);
4949501SRobert.Johnston@Sun.COM return (NULL);
4959501SRobert.Johnston@Sun.COM }
4969501SRobert.Johnston@Sun.COM
4979501SRobert.Johnston@Sun.COM return (s);
4989501SRobert.Johnston@Sun.COM }
4999501SRobert.Johnston@Sun.COM
5009501SRobert.Johnston@Sun.COM /*
5019501SRobert.Johnston@Sun.COM * Buffer utility function to write a wide-character string into the buffer,
5029501SRobert.Johnston@Sun.COM * appending it at the end, and growing the buffer as needed as we go. Any
5039501SRobert.Johnston@Sun.COM * allocation errors are stored in fmb_error and deferred until later.
5049501SRobert.Johnston@Sun.COM */
5059501SRobert.Johnston@Sun.COM static void
fmd_msg_buf_write(fmd_msg_buf_t * b,const wchar_t * w,size_t n)5069501SRobert.Johnston@Sun.COM fmd_msg_buf_write(fmd_msg_buf_t *b, const wchar_t *w, size_t n)
5079501SRobert.Johnston@Sun.COM {
5089501SRobert.Johnston@Sun.COM if (b->fmb_used + n > b->fmb_size) {
5099501SRobert.Johnston@Sun.COM size_t size = MAX(b->fmb_size * 2, b->fmb_used + n);
5109501SRobert.Johnston@Sun.COM wchar_t *data = malloc(sizeof (wchar_t) * size);
5119501SRobert.Johnston@Sun.COM
5129501SRobert.Johnston@Sun.COM if (data == NULL) {
5139501SRobert.Johnston@Sun.COM if (b->fmb_error == 0)
5149501SRobert.Johnston@Sun.COM b->fmb_error = ENOMEM;
5159501SRobert.Johnston@Sun.COM return;
5169501SRobert.Johnston@Sun.COM }
5179501SRobert.Johnston@Sun.COM
5189501SRobert.Johnston@Sun.COM bcopy(b->fmb_data, data, b->fmb_used * sizeof (wchar_t));
5199501SRobert.Johnston@Sun.COM free(b->fmb_data);
5209501SRobert.Johnston@Sun.COM
5219501SRobert.Johnston@Sun.COM b->fmb_data = data;
5229501SRobert.Johnston@Sun.COM b->fmb_size = size;
5239501SRobert.Johnston@Sun.COM }
5249501SRobert.Johnston@Sun.COM
5259501SRobert.Johnston@Sun.COM bcopy(w, &b->fmb_data[b->fmb_used], sizeof (wchar_t) * n);
5269501SRobert.Johnston@Sun.COM b->fmb_used += n;
5279501SRobert.Johnston@Sun.COM }
5289501SRobert.Johnston@Sun.COM
5299501SRobert.Johnston@Sun.COM /*
5309501SRobert.Johnston@Sun.COM * Buffer utility function to printf a multi-byte string, convert to wide-
5319501SRobert.Johnston@Sun.COM * character form, and then write the result into an fmd_msg_buf_t.
5329501SRobert.Johnston@Sun.COM */
5339501SRobert.Johnston@Sun.COM /*PRINTFLIKE2*/
5349501SRobert.Johnston@Sun.COM static void
fmd_msg_buf_printf(fmd_msg_buf_t * b,const char * format,...)5359501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(fmd_msg_buf_t *b, const char *format, ...)
5369501SRobert.Johnston@Sun.COM {
5379501SRobert.Johnston@Sun.COM ssize_t len;
5389501SRobert.Johnston@Sun.COM va_list ap;
5399501SRobert.Johnston@Sun.COM char *buf;
5409501SRobert.Johnston@Sun.COM wchar_t *w;
5419501SRobert.Johnston@Sun.COM
5429501SRobert.Johnston@Sun.COM va_start(ap, format);
5439501SRobert.Johnston@Sun.COM len = vsnprintf(NULL, 0, format, ap);
5449501SRobert.Johnston@Sun.COM buf = alloca(len + 1);
5459501SRobert.Johnston@Sun.COM (void) vsnprintf(buf, len + 1, format, ap);
5469501SRobert.Johnston@Sun.COM va_end(ap);
5479501SRobert.Johnston@Sun.COM
5489501SRobert.Johnston@Sun.COM if ((w = fmd_msg_mbstowcs(buf)) == NULL) {
5499501SRobert.Johnston@Sun.COM if (b->fmb_error != 0)
5509501SRobert.Johnston@Sun.COM b->fmb_error = errno;
5519501SRobert.Johnston@Sun.COM } else {
5529501SRobert.Johnston@Sun.COM fmd_msg_buf_write(b, w, wcslen(w));
5539501SRobert.Johnston@Sun.COM free(w);
5549501SRobert.Johnston@Sun.COM }
5559501SRobert.Johnston@Sun.COM }
5569501SRobert.Johnston@Sun.COM
5579501SRobert.Johnston@Sun.COM /*PRINTFLIKE1*/
5589501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_error(const char * format,...)5599501SRobert.Johnston@Sun.COM fmd_msg_nv_error(const char *format, ...)
5609501SRobert.Johnston@Sun.COM {
5619501SRobert.Johnston@Sun.COM int err = errno;
5629501SRobert.Johnston@Sun.COM va_list ap;
5639501SRobert.Johnston@Sun.COM
5649501SRobert.Johnston@Sun.COM if (getenv("FMD_MSG_DEBUG") == NULL)
5659501SRobert.Johnston@Sun.COM return (1);
5669501SRobert.Johnston@Sun.COM
5679501SRobert.Johnston@Sun.COM (void) fprintf(stderr, "libfmd_msg DEBUG: ");
5689501SRobert.Johnston@Sun.COM va_start(ap, format);
5699501SRobert.Johnston@Sun.COM (void) vfprintf(stderr, format, ap);
5709501SRobert.Johnston@Sun.COM va_end(ap);
5719501SRobert.Johnston@Sun.COM
5729501SRobert.Johnston@Sun.COM if (strchr(format, '\n') == NULL)
5739501SRobert.Johnston@Sun.COM (void) fprintf(stderr, ": %s\n", strerror(err));
5749501SRobert.Johnston@Sun.COM
5759501SRobert.Johnston@Sun.COM return (1);
5769501SRobert.Johnston@Sun.COM }
5779501SRobert.Johnston@Sun.COM
5789501SRobert.Johnston@Sun.COM static const struct fmd_msg_nv_type *
fmd_msg_nv_type_lookup(data_type_t type)5799501SRobert.Johnston@Sun.COM fmd_msg_nv_type_lookup(data_type_t type)
5809501SRobert.Johnston@Sun.COM {
5819501SRobert.Johnston@Sun.COM const struct fmd_msg_nv_type *t;
5829501SRobert.Johnston@Sun.COM
5839501SRobert.Johnston@Sun.COM for (t = fmd_msg_nv_types; t->nvt_type != DATA_TYPE_UNKNOWN; t++) {
5849501SRobert.Johnston@Sun.COM if (t->nvt_type == type)
5859501SRobert.Johnston@Sun.COM break;
5869501SRobert.Johnston@Sun.COM }
5879501SRobert.Johnston@Sun.COM
5889501SRobert.Johnston@Sun.COM return (t);
5899501SRobert.Johnston@Sun.COM }
5909501SRobert.Johnston@Sun.COM
5919501SRobert.Johnston@Sun.COM /*
5929501SRobert.Johnston@Sun.COM * Print the specified string, escaping any unprintable character sequences
5939501SRobert.Johnston@Sun.COM * using the ISO C character escape sequences.
5949501SRobert.Johnston@Sun.COM */
5959501SRobert.Johnston@Sun.COM static void
fmd_msg_nv_print_string(fmd_msg_buf_t * b,const char * s)5969501SRobert.Johnston@Sun.COM fmd_msg_nv_print_string(fmd_msg_buf_t *b, const char *s)
5979501SRobert.Johnston@Sun.COM {
5989501SRobert.Johnston@Sun.COM char c;
5999501SRobert.Johnston@Sun.COM
6009501SRobert.Johnston@Sun.COM while ((c = *s++) != '\0') {
6019501SRobert.Johnston@Sun.COM if (c >= ' ' && c <= '~' && c != '\'') {
6029501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%c", c);
6039501SRobert.Johnston@Sun.COM continue;
6049501SRobert.Johnston@Sun.COM }
6059501SRobert.Johnston@Sun.COM
6069501SRobert.Johnston@Sun.COM switch (c) {
6079501SRobert.Johnston@Sun.COM case '\0':
6089501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\0");
6099501SRobert.Johnston@Sun.COM break;
6109501SRobert.Johnston@Sun.COM case '\a':
6119501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\a");
6129501SRobert.Johnston@Sun.COM break;
6139501SRobert.Johnston@Sun.COM case '\b':
6149501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\b");
6159501SRobert.Johnston@Sun.COM break;
6169501SRobert.Johnston@Sun.COM case '\f':
6179501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\f");
6189501SRobert.Johnston@Sun.COM break;
6199501SRobert.Johnston@Sun.COM case '\n':
6209501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\n");
6219501SRobert.Johnston@Sun.COM break;
6229501SRobert.Johnston@Sun.COM case '\r':
6239501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\r");
6249501SRobert.Johnston@Sun.COM break;
6259501SRobert.Johnston@Sun.COM case '\t':
6269501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\t");
6279501SRobert.Johnston@Sun.COM break;
6289501SRobert.Johnston@Sun.COM case '\v':
6299501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\v");
6309501SRobert.Johnston@Sun.COM break;
6319501SRobert.Johnston@Sun.COM case '\'':
6329501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\'");
6339501SRobert.Johnston@Sun.COM break;
6349501SRobert.Johnston@Sun.COM case '"':
6359501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\\"");
6369501SRobert.Johnston@Sun.COM break;
6379501SRobert.Johnston@Sun.COM case '\\':
6389501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\\\");
6399501SRobert.Johnston@Sun.COM break;
6409501SRobert.Johnston@Sun.COM default:
6419501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "\\x%02x", (uchar_t)c);
6429501SRobert.Johnston@Sun.COM }
6439501SRobert.Johnston@Sun.COM }
6449501SRobert.Johnston@Sun.COM }
6459501SRobert.Johnston@Sun.COM
6469501SRobert.Johnston@Sun.COM /*
6479501SRobert.Johnston@Sun.COM * Print the value of the specified nvpair into the supplied buffer.
6489501SRobert.Johnston@Sun.COM *
6499501SRobert.Johnston@Sun.COM * For nvpairs that are arrays types, passing -1 as the idx param indicates
6509501SRobert.Johnston@Sun.COM * that we want to print all of the elements in the array.
6519501SRobert.Johnston@Sun.COM *
6529501SRobert.Johnston@Sun.COM * Returns 0 on success, 1 otherwise.
6539501SRobert.Johnston@Sun.COM */
6549501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_print_items(fmd_msg_buf_t * b,nvpair_t * nvp,data_type_t type,void * p,uint_t n,uint_t idx)6559501SRobert.Johnston@Sun.COM fmd_msg_nv_print_items(fmd_msg_buf_t *b, nvpair_t *nvp,
6569501SRobert.Johnston@Sun.COM data_type_t type, void *p, uint_t n, uint_t idx)
6579501SRobert.Johnston@Sun.COM {
6589501SRobert.Johnston@Sun.COM const struct fmd_msg_nv_type *nvt = fmd_msg_nv_type_lookup(type);
6599501SRobert.Johnston@Sun.COM uint_t i;
6609501SRobert.Johnston@Sun.COM
6619501SRobert.Johnston@Sun.COM if (idx != -1u) {
6629501SRobert.Johnston@Sun.COM if (idx >= n) {
6639501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("index %u out-of-range for "
6649501SRobert.Johnston@Sun.COM "array %s: valid range is [0 .. %u]\n",
6659501SRobert.Johnston@Sun.COM idx, nvpair_name(nvp), n ? n - 1 : 0));
6669501SRobert.Johnston@Sun.COM }
6679501SRobert.Johnston@Sun.COM p = (uchar_t *)p + nvt->nvt_size * idx;
6689501SRobert.Johnston@Sun.COM n = 1;
6699501SRobert.Johnston@Sun.COM }
6709501SRobert.Johnston@Sun.COM
6719501SRobert.Johnston@Sun.COM for (i = 0; i < n; i++, p = (uchar_t *)p + nvt->nvt_size) {
6729501SRobert.Johnston@Sun.COM if (i > 0)
6739501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, " "); /* array item delimiter */
6749501SRobert.Johnston@Sun.COM
6759501SRobert.Johnston@Sun.COM switch (type) {
6769501SRobert.Johnston@Sun.COM case DATA_TYPE_INT8:
6779501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%d", *(int8_t *)p);
6789501SRobert.Johnston@Sun.COM break;
6799501SRobert.Johnston@Sun.COM
6809501SRobert.Johnston@Sun.COM case DATA_TYPE_INT16:
6819501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%d", *(int16_t *)p);
6829501SRobert.Johnston@Sun.COM break;
6839501SRobert.Johnston@Sun.COM
6849501SRobert.Johnston@Sun.COM case DATA_TYPE_INT32:
6859501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%d", *(int32_t *)p);
6869501SRobert.Johnston@Sun.COM break;
6879501SRobert.Johnston@Sun.COM
6889501SRobert.Johnston@Sun.COM case DATA_TYPE_INT64:
6899501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%lld", *(longlong_t *)p);
6909501SRobert.Johnston@Sun.COM break;
6919501SRobert.Johnston@Sun.COM
6929501SRobert.Johnston@Sun.COM case DATA_TYPE_UINT8:
6939501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%u", *(uint8_t *)p);
6949501SRobert.Johnston@Sun.COM break;
6959501SRobert.Johnston@Sun.COM
6969501SRobert.Johnston@Sun.COM case DATA_TYPE_UINT16:
6979501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%u", *(uint16_t *)p);
6989501SRobert.Johnston@Sun.COM break;
6999501SRobert.Johnston@Sun.COM
7009501SRobert.Johnston@Sun.COM case DATA_TYPE_UINT32:
7019501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%u", *(uint32_t *)p);
7029501SRobert.Johnston@Sun.COM break;
7039501SRobert.Johnston@Sun.COM
7049501SRobert.Johnston@Sun.COM case DATA_TYPE_UINT64:
7059501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%llu", *(u_longlong_t *)p);
7069501SRobert.Johnston@Sun.COM break;
7079501SRobert.Johnston@Sun.COM
7089501SRobert.Johnston@Sun.COM case DATA_TYPE_BYTE:
7099501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "0x%x", *(uchar_t *)p);
7109501SRobert.Johnston@Sun.COM break;
7119501SRobert.Johnston@Sun.COM
7129501SRobert.Johnston@Sun.COM case DATA_TYPE_BOOLEAN_VALUE:
7139501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b,
7149501SRobert.Johnston@Sun.COM *(boolean_t *)p ? "true" : "false");
7159501SRobert.Johnston@Sun.COM break;
7169501SRobert.Johnston@Sun.COM
7179501SRobert.Johnston@Sun.COM case DATA_TYPE_HRTIME:
7189501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "%lld", *(longlong_t *)p);
7199501SRobert.Johnston@Sun.COM break;
7209501SRobert.Johnston@Sun.COM
7219501SRobert.Johnston@Sun.COM case DATA_TYPE_STRING:
7229501SRobert.Johnston@Sun.COM fmd_msg_nv_print_string(b, *(char **)p);
7239501SRobert.Johnston@Sun.COM break;
7249501SRobert.Johnston@Sun.COM }
7259501SRobert.Johnston@Sun.COM }
7269501SRobert.Johnston@Sun.COM
7279501SRobert.Johnston@Sun.COM return (0);
7289501SRobert.Johnston@Sun.COM }
7299501SRobert.Johnston@Sun.COM
7309501SRobert.Johnston@Sun.COM /*
7319501SRobert.Johnston@Sun.COM * Writes the value of the specified nvpair to the supplied buffer.
7329501SRobert.Johnston@Sun.COM *
7339501SRobert.Johnston@Sun.COM * Returns 0 on success, 1 otherwise.
7349501SRobert.Johnston@Sun.COM */
7359501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_print_nvpair(fmd_msg_buf_t * b,nvpair_t * nvp,uint_t idx)7369501SRobert.Johnston@Sun.COM fmd_msg_nv_print_nvpair(fmd_msg_buf_t *b, nvpair_t *nvp, uint_t idx)
7379501SRobert.Johnston@Sun.COM {
7389501SRobert.Johnston@Sun.COM data_type_t type = nvpair_type(nvp);
7399501SRobert.Johnston@Sun.COM const struct fmd_msg_nv_type *nvt = fmd_msg_nv_type_lookup(type);
7409501SRobert.Johnston@Sun.COM
7419501SRobert.Johnston@Sun.COM uint64_t v;
7429501SRobert.Johnston@Sun.COM void *a;
7439501SRobert.Johnston@Sun.COM uint_t n;
7449501SRobert.Johnston@Sun.COM int err;
7459501SRobert.Johnston@Sun.COM
7469501SRobert.Johnston@Sun.COM if (nvt->nvt_type == DATA_TYPE_BOOLEAN) {
7479501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(b, "true");
7489501SRobert.Johnston@Sun.COM err = 0;
7499501SRobert.Johnston@Sun.COM } else if (nvt->nvt_array != NULL) {
7509501SRobert.Johnston@Sun.COM (void) nvt->nvt_array(nvp, &a, &n);
7519501SRobert.Johnston@Sun.COM err = fmd_msg_nv_print_items(b, nvp, nvt->nvt_base, a, n, idx);
7529501SRobert.Johnston@Sun.COM } else if (nvt->nvt_value != NULL) {
7539501SRobert.Johnston@Sun.COM (void) nvt->nvt_value(nvp, &v);
7549501SRobert.Johnston@Sun.COM err = fmd_msg_nv_print_items(b, nvp, nvt->nvt_base, &v, 1, idx);
7559501SRobert.Johnston@Sun.COM } else {
7569501SRobert.Johnston@Sun.COM err = fmd_msg_nv_error("unknown data type %u", type);
7579501SRobert.Johnston@Sun.COM }
7589501SRobert.Johnston@Sun.COM
7599501SRobert.Johnston@Sun.COM return (err);
7609501SRobert.Johnston@Sun.COM }
7619501SRobert.Johnston@Sun.COM
7629501SRobert.Johnston@Sun.COM /*
7639501SRobert.Johnston@Sun.COM * Consume a token from the specified string, fill in the specified token
7649501SRobert.Johnston@Sun.COM * struct, and return the new string position from which to continue parsing.
7659501SRobert.Johnston@Sun.COM */
7669501SRobert.Johnston@Sun.COM static char *
fmd_msg_nv_parse_token(char * s,fmd_msg_nv_token_t * tp)7679501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_token(char *s, fmd_msg_nv_token_t *tp)
7689501SRobert.Johnston@Sun.COM {
7699501SRobert.Johnston@Sun.COM char *p = s, *q, c = *s;
7709501SRobert.Johnston@Sun.COM
7719501SRobert.Johnston@Sun.COM /*
7729501SRobert.Johnston@Sun.COM * Skip whitespace and then look for an integer token first. We can't
7739501SRobert.Johnston@Sun.COM * use isspace() or isdigit() because we're in setlocale() context now.
7749501SRobert.Johnston@Sun.COM */
7759501SRobert.Johnston@Sun.COM while (c == ' ' || c == '\t' || c == '\v' || c == '\n' || c == '\r')
7769501SRobert.Johnston@Sun.COM c = *++p;
7779501SRobert.Johnston@Sun.COM
7789501SRobert.Johnston@Sun.COM if (c >= '0' && c <= '9') {
7799501SRobert.Johnston@Sun.COM errno = 0;
7809501SRobert.Johnston@Sun.COM tp->t_data.tu_int = strtoul(p, &q, 0);
7819501SRobert.Johnston@Sun.COM
7829501SRobert.Johnston@Sun.COM if (errno != 0 || p == q) {
7839501SRobert.Johnston@Sun.COM tp->t_kind = T_ERR;
7849501SRobert.Johnston@Sun.COM return (p);
7859501SRobert.Johnston@Sun.COM }
7869501SRobert.Johnston@Sun.COM
7879501SRobert.Johnston@Sun.COM tp->t_kind = T_INT;
7889501SRobert.Johnston@Sun.COM return (q);
7899501SRobert.Johnston@Sun.COM }
7909501SRobert.Johnston@Sun.COM
7919501SRobert.Johnston@Sun.COM /*
7929501SRobert.Johnston@Sun.COM * Look for a name-value pair identifier, which we define to be the
7939501SRobert.Johnston@Sun.COM * regular expression [a-zA-Z_][a-zA-Z0-9_-]* (NOTE: Ideally "-" would
7949501SRobert.Johnston@Sun.COM * not be allowed here and we would require ISO C identifiers, but many
7959501SRobert.Johnston@Sun.COM * FMA event members use hyphens.) This code specifically cannot use
7969501SRobert.Johnston@Sun.COM * the isspace(), isalnum() etc. macros because we are currently in the
7979501SRobert.Johnston@Sun.COM * context of an earlier call to setlocale() that may have installed a
7989501SRobert.Johnston@Sun.COM * non-C locale, but this code needs to always operate on C characters.
7999501SRobert.Johnston@Sun.COM */
8009501SRobert.Johnston@Sun.COM if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') {
8019501SRobert.Johnston@Sun.COM for (q = p + 1; (c = *q) != '\0'; q++) {
8029501SRobert.Johnston@Sun.COM if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&
8039501SRobert.Johnston@Sun.COM (c < '0' || c > '9') && (c != '_' && c != '-'))
8049501SRobert.Johnston@Sun.COM break;
8059501SRobert.Johnston@Sun.COM }
8069501SRobert.Johnston@Sun.COM
8079501SRobert.Johnston@Sun.COM if (sizeof (tp->t_data.tu_str) <= (size_t)(q - p)) {
8089501SRobert.Johnston@Sun.COM tp->t_kind = T_ERR;
8099501SRobert.Johnston@Sun.COM return (p);
8109501SRobert.Johnston@Sun.COM }
8119501SRobert.Johnston@Sun.COM
8129501SRobert.Johnston@Sun.COM bcopy(p, tp->t_data.tu_str, (size_t)(q - p));
8139501SRobert.Johnston@Sun.COM tp->t_data.tu_str[(size_t)(q - p)] = '\0';
8149501SRobert.Johnston@Sun.COM tp->t_kind = T_IDENT;
8159501SRobert.Johnston@Sun.COM return (q);
8169501SRobert.Johnston@Sun.COM }
8179501SRobert.Johnston@Sun.COM
8189501SRobert.Johnston@Sun.COM switch (c) {
8199501SRobert.Johnston@Sun.COM case '\0':
8209501SRobert.Johnston@Sun.COM tp->t_kind = T_EOF;
8219501SRobert.Johnston@Sun.COM return (p);
8229501SRobert.Johnston@Sun.COM case '.':
8239501SRobert.Johnston@Sun.COM tp->t_kind = T_DOT;
8249501SRobert.Johnston@Sun.COM return (p + 1);
8259501SRobert.Johnston@Sun.COM case '[':
8269501SRobert.Johnston@Sun.COM tp->t_kind = T_LBRAC;
8279501SRobert.Johnston@Sun.COM return (p + 1);
8289501SRobert.Johnston@Sun.COM case ']':
8299501SRobert.Johnston@Sun.COM tp->t_kind = T_RBRAC;
8309501SRobert.Johnston@Sun.COM return (p + 1);
8319501SRobert.Johnston@Sun.COM default:
8329501SRobert.Johnston@Sun.COM tp->t_kind = T_ERR;
8339501SRobert.Johnston@Sun.COM return (p);
8349501SRobert.Johnston@Sun.COM }
8359501SRobert.Johnston@Sun.COM }
8369501SRobert.Johnston@Sun.COM
8379501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_parse_error(const char * s,fmd_msg_nv_token_t * tp)8389501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_error(const char *s, fmd_msg_nv_token_t *tp)
8399501SRobert.Johnston@Sun.COM {
8409501SRobert.Johnston@Sun.COM if (tp->t_kind == T_ERR)
8419501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("illegal character at \"%s\"\n", s));
8429501SRobert.Johnston@Sun.COM else
8439501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("syntax error near \"%s\"\n", s));
8449501SRobert.Johnston@Sun.COM }
8459501SRobert.Johnston@Sun.COM
8469501SRobert.Johnston@Sun.COM /*
8479501SRobert.Johnston@Sun.COM * Parse an array expression for referencing an element of the specified
8489501SRobert.Johnston@Sun.COM * nvpair_t, which is expected to be of an array type. If it's an array of
8499501SRobert.Johnston@Sun.COM * intrinsics, print the specified value. If it's an array of nvlist_t's,
8509501SRobert.Johnston@Sun.COM * call fmd_msg_nv_parse_nvlist() recursively to continue parsing.
8519501SRobert.Johnston@Sun.COM */
8529501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_parse_array(fmd_msg_buf_t * b,nvpair_t * nvp,char * s1)8539501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_array(fmd_msg_buf_t *b, nvpair_t *nvp, char *s1)
8549501SRobert.Johnston@Sun.COM {
8559501SRobert.Johnston@Sun.COM fmd_msg_nv_token_t t;
8569501SRobert.Johnston@Sun.COM nvlist_t **nva;
8579501SRobert.Johnston@Sun.COM uint_t i, n;
8589501SRobert.Johnston@Sun.COM char *s2;
8599501SRobert.Johnston@Sun.COM
8609501SRobert.Johnston@Sun.COM if (fmd_msg_nv_type_lookup(nvpair_type(nvp))->nvt_array == NULL) {
8619501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("inappropriate use of operator [ ]: "
8629501SRobert.Johnston@Sun.COM "element '%s' is not an array\n", nvpair_name(nvp)));
8639501SRobert.Johnston@Sun.COM }
8649501SRobert.Johnston@Sun.COM
8659501SRobert.Johnston@Sun.COM s2 = fmd_msg_nv_parse_token(s1, &t);
8669501SRobert.Johnston@Sun.COM i = t.t_data.tu_int;
8679501SRobert.Johnston@Sun.COM
8689501SRobert.Johnston@Sun.COM if (t.t_kind != T_INT)
8699501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("expected integer index after [\n"));
8709501SRobert.Johnston@Sun.COM
8719501SRobert.Johnston@Sun.COM s2 = fmd_msg_nv_parse_token(s2, &t);
8729501SRobert.Johnston@Sun.COM
8739501SRobert.Johnston@Sun.COM if (t.t_kind != T_RBRAC)
8749501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("expected ] after [ %u\n", i));
8759501SRobert.Johnston@Sun.COM
8769501SRobert.Johnston@Sun.COM /*
8779501SRobert.Johnston@Sun.COM * An array of nvlist is different from other array types in that it
8789501SRobert.Johnston@Sun.COM * permits us to continue parsing instead of printing a terminal node.
8799501SRobert.Johnston@Sun.COM */
8809501SRobert.Johnston@Sun.COM if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
8819501SRobert.Johnston@Sun.COM (void) nvpair_value_nvlist_array(nvp, &nva, &n);
8829501SRobert.Johnston@Sun.COM
8839501SRobert.Johnston@Sun.COM if (i >= n) {
8849501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("index %u out-of-range for "
8859501SRobert.Johnston@Sun.COM "array %s: valid range is [0 .. %u]\n",
8869501SRobert.Johnston@Sun.COM i, nvpair_name(nvp), n ? n - 1 : 0));
8879501SRobert.Johnston@Sun.COM }
8889501SRobert.Johnston@Sun.COM
8899501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_nvlist(b, nva[i], s2));
8909501SRobert.Johnston@Sun.COM }
8919501SRobert.Johnston@Sun.COM
8929501SRobert.Johnston@Sun.COM (void) fmd_msg_nv_parse_token(s2, &t);
8939501SRobert.Johnston@Sun.COM
8949501SRobert.Johnston@Sun.COM if (t.t_kind != T_EOF) {
8959501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("expected end-of-string "
8969501SRobert.Johnston@Sun.COM "in expression instead of \"%s\"\n", s2));
8979501SRobert.Johnston@Sun.COM }
8989501SRobert.Johnston@Sun.COM
8999501SRobert.Johnston@Sun.COM return (fmd_msg_nv_print_nvpair(b, nvp, i));
9009501SRobert.Johnston@Sun.COM }
9019501SRobert.Johnston@Sun.COM
9029501SRobert.Johnston@Sun.COM /*
9039501SRobert.Johnston@Sun.COM * Parse an expression rooted at an nvpair_t. If we see EOF, print the entire
9049501SRobert.Johnston@Sun.COM * nvpair. If we see LBRAC, parse an array expression. If we see DOT, call
9059501SRobert.Johnston@Sun.COM * fmd_msg_nv_parse_nvname() recursively to dereference an embedded member.
9069501SRobert.Johnston@Sun.COM */
9079501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_parse_nvpair(fmd_msg_buf_t * b,nvpair_t * nvp,char * s1)9089501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_nvpair(fmd_msg_buf_t *b, nvpair_t *nvp, char *s1)
9099501SRobert.Johnston@Sun.COM {
9109501SRobert.Johnston@Sun.COM fmd_msg_nv_token_t t;
9119501SRobert.Johnston@Sun.COM nvlist_t *nvl;
9129501SRobert.Johnston@Sun.COM char *s2;
9139501SRobert.Johnston@Sun.COM
9149501SRobert.Johnston@Sun.COM s2 = fmd_msg_nv_parse_token(s1, &t);
9159501SRobert.Johnston@Sun.COM
9169501SRobert.Johnston@Sun.COM if (t.t_kind == T_EOF)
9179501SRobert.Johnston@Sun.COM return (fmd_msg_nv_print_nvpair(b, nvp, -1));
9189501SRobert.Johnston@Sun.COM
9199501SRobert.Johnston@Sun.COM if (t.t_kind == T_LBRAC)
9209501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_array(b, nvp, s2));
9219501SRobert.Johnston@Sun.COM
9229501SRobert.Johnston@Sun.COM if (t.t_kind != T_DOT)
9239501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_error(s1, &t));
9249501SRobert.Johnston@Sun.COM
9259501SRobert.Johnston@Sun.COM if (nvpair_type(nvp) != DATA_TYPE_NVLIST) {
9269501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("inappropriate use of operator '.': "
9279501SRobert.Johnston@Sun.COM "element '%s' is not of type nvlist\n", nvpair_name(nvp)));
9289501SRobert.Johnston@Sun.COM }
9299501SRobert.Johnston@Sun.COM
9309501SRobert.Johnston@Sun.COM (void) nvpair_value_nvlist(nvp, &nvl);
9319501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_nvname(b, nvl, s2));
9329501SRobert.Johnston@Sun.COM }
9339501SRobert.Johnston@Sun.COM
9349501SRobert.Johnston@Sun.COM /*
9359501SRobert.Johnston@Sun.COM * Parse an expression for a name-value pair name (IDENT). If we find a match
9369501SRobert.Johnston@Sun.COM * continue parsing with the corresponding nvpair_t.
9379501SRobert.Johnston@Sun.COM */
9389501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_parse_nvname(fmd_msg_buf_t * b,nvlist_t * nvl,char * s1)9399501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_nvname(fmd_msg_buf_t *b, nvlist_t *nvl, char *s1)
9409501SRobert.Johnston@Sun.COM {
9419501SRobert.Johnston@Sun.COM nvpair_t *nvp = NULL;
9429501SRobert.Johnston@Sun.COM fmd_msg_nv_token_t t;
9439501SRobert.Johnston@Sun.COM char *s2;
9449501SRobert.Johnston@Sun.COM
9459501SRobert.Johnston@Sun.COM s2 = fmd_msg_nv_parse_token(s1, &t);
9469501SRobert.Johnston@Sun.COM
9479501SRobert.Johnston@Sun.COM if (t.t_kind != T_IDENT)
9489501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_error(s1, &t));
9499501SRobert.Johnston@Sun.COM
9509501SRobert.Johnston@Sun.COM while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
9519501SRobert.Johnston@Sun.COM if (strcmp(nvpair_name(nvp), t.t_data.tu_str) == 0)
9529501SRobert.Johnston@Sun.COM break;
9539501SRobert.Johnston@Sun.COM }
9549501SRobert.Johnston@Sun.COM
9559501SRobert.Johnston@Sun.COM if (nvp == NULL) {
9569501SRobert.Johnston@Sun.COM return (fmd_msg_nv_error("no such name-value pair "
9579501SRobert.Johnston@Sun.COM "member: %s\n", t.t_data.tu_str));
9589501SRobert.Johnston@Sun.COM }
9599501SRobert.Johnston@Sun.COM
9609501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_nvpair(b, nvp, s2));
9619501SRobert.Johnston@Sun.COM }
9629501SRobert.Johnston@Sun.COM
9639501SRobert.Johnston@Sun.COM /*
9649501SRobert.Johnston@Sun.COM * Parse an expression rooted at an nvlist: if we see EOF, print nothing.
9659501SRobert.Johnston@Sun.COM * If we see DOT, continue parsing to retrieve a name-value pair name.
9669501SRobert.Johnston@Sun.COM */
9679501SRobert.Johnston@Sun.COM static int
fmd_msg_nv_parse_nvlist(fmd_msg_buf_t * b,nvlist_t * nvl,char * s1)9689501SRobert.Johnston@Sun.COM fmd_msg_nv_parse_nvlist(fmd_msg_buf_t *b, nvlist_t *nvl, char *s1)
9699501SRobert.Johnston@Sun.COM {
9709501SRobert.Johnston@Sun.COM fmd_msg_nv_token_t t;
9719501SRobert.Johnston@Sun.COM char *s2;
9729501SRobert.Johnston@Sun.COM
9739501SRobert.Johnston@Sun.COM s2 = fmd_msg_nv_parse_token(s1, &t);
9749501SRobert.Johnston@Sun.COM
9759501SRobert.Johnston@Sun.COM if (t.t_kind == T_EOF)
9769501SRobert.Johnston@Sun.COM return (0);
9779501SRobert.Johnston@Sun.COM
9789501SRobert.Johnston@Sun.COM if (t.t_kind == T_DOT)
9799501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_nvname(b, nvl, s2));
9809501SRobert.Johnston@Sun.COM
9819501SRobert.Johnston@Sun.COM return (fmd_msg_nv_parse_error(s1, &t));
9829501SRobert.Johnston@Sun.COM }
9839501SRobert.Johnston@Sun.COM
9849501SRobert.Johnston@Sun.COM /*
9859501SRobert.Johnston@Sun.COM * This function is the main engine for formatting an event message item, such
9869501SRobert.Johnston@Sun.COM * as the Description field. It loads the item text from a message object,
9879501SRobert.Johnston@Sun.COM * expands any variables defined in the item text, and then returns a newly-
9889501SRobert.Johnston@Sun.COM * allocated multi-byte string with the localized message text, or NULL with
9899501SRobert.Johnston@Sun.COM * errno set if an error occurred.
9909501SRobert.Johnston@Sun.COM */
9919501SRobert.Johnston@Sun.COM static char *
fmd_msg_getitem_locked(fmd_msg_hdl_t * h,nvlist_t * nvl,const char * dict,const char * code,fmd_msg_item_t item)9929501SRobert.Johnston@Sun.COM fmd_msg_getitem_locked(fmd_msg_hdl_t *h,
9939501SRobert.Johnston@Sun.COM nvlist_t *nvl, const char *dict, const char *code, fmd_msg_item_t item)
9949501SRobert.Johnston@Sun.COM {
9959501SRobert.Johnston@Sun.COM const char *istr = fmd_msg_items[item];
9969501SRobert.Johnston@Sun.COM size_t len = strlen(code) + 1 + strlen(istr) + 1;
9979501SRobert.Johnston@Sun.COM char *key = alloca(len);
9989501SRobert.Johnston@Sun.COM
9999501SRobert.Johnston@Sun.COM fmd_msg_buf_t buf;
10009501SRobert.Johnston@Sun.COM wchar_t *c, *u, *w, *p, *q;
10019501SRobert.Johnston@Sun.COM
10029501SRobert.Johnston@Sun.COM const char *url, *txt;
10039501SRobert.Johnston@Sun.COM char *s, *expr;
10049501SRobert.Johnston@Sun.COM size_t elen;
10059501SRobert.Johnston@Sun.COM int i;
10069501SRobert.Johnston@Sun.COM
10079501SRobert.Johnston@Sun.COM assert(fmd_msg_lock_held(h));
10089501SRobert.Johnston@Sun.COM
10099501SRobert.Johnston@Sun.COM /*
10109501SRobert.Johnston@Sun.COM * If <dict>.mo defines an item with the key <FMD_MSG_URLKEY> then it
10119501SRobert.Johnston@Sun.COM * is used as the URL; otherwise the default from our handle is used.
10129501SRobert.Johnston@Sun.COM * Once we have the multi-byte URL, convert it to wide-character form.
10139501SRobert.Johnston@Sun.COM */
10149501SRobert.Johnston@Sun.COM if ((url = dgettext(dict, FMD_MSG_URLKEY)) == FMD_MSG_URLKEY)
10159501SRobert.Johnston@Sun.COM url = h->fmh_urlbase;
10169501SRobert.Johnston@Sun.COM
10179501SRobert.Johnston@Sun.COM /*
10189501SRobert.Johnston@Sun.COM * If the item is FMD_MSG_ITEM_URL, then its value is directly computed
10199501SRobert.Johnston@Sun.COM * as the URL base concatenated with the code. Otherwise the item text
10209501SRobert.Johnston@Sun.COM * is derived by looking up the key <code>.<istr> in the dict object.
10219501SRobert.Johnston@Sun.COM * Once we're done, convert the 'txt' multi-byte to wide-character.
10229501SRobert.Johnston@Sun.COM */
10239501SRobert.Johnston@Sun.COM if (item == FMD_MSG_ITEM_URL) {
10249501SRobert.Johnston@Sun.COM len = strlen(url) + strlen(code) + 1;
10259501SRobert.Johnston@Sun.COM key = alloca(len);
10269501SRobert.Johnston@Sun.COM (void) snprintf(key, len, "%s%s", url, code);
10279501SRobert.Johnston@Sun.COM txt = key;
10289501SRobert.Johnston@Sun.COM } else {
10299501SRobert.Johnston@Sun.COM len = strlen(code) + 1 + strlen(istr) + 1;
10309501SRobert.Johnston@Sun.COM key = alloca(len);
10319501SRobert.Johnston@Sun.COM (void) snprintf(key, len, "%s.%s", code, istr);
10329501SRobert.Johnston@Sun.COM txt = dgettext(dict, key);
10339501SRobert.Johnston@Sun.COM }
10349501SRobert.Johnston@Sun.COM
10359501SRobert.Johnston@Sun.COM c = fmd_msg_mbstowcs(code);
10369501SRobert.Johnston@Sun.COM u = fmd_msg_mbstowcs(url);
10379501SRobert.Johnston@Sun.COM w = fmd_msg_mbstowcs(txt);
10389501SRobert.Johnston@Sun.COM
10399501SRobert.Johnston@Sun.COM if (c == NULL || u == NULL || w == NULL) {
10409501SRobert.Johnston@Sun.COM free(c);
10419501SRobert.Johnston@Sun.COM free(u);
10429501SRobert.Johnston@Sun.COM free(w);
10439501SRobert.Johnston@Sun.COM return (NULL);
10449501SRobert.Johnston@Sun.COM }
10459501SRobert.Johnston@Sun.COM
10469501SRobert.Johnston@Sun.COM /*
10479501SRobert.Johnston@Sun.COM * Now expand any escape sequences in the string, storing the final
10489501SRobert.Johnston@Sun.COM * text in 'buf' in wide-character format, and then convert it back
10499501SRobert.Johnston@Sun.COM * to multi-byte for return. We expand the following sequences:
10509501SRobert.Johnston@Sun.COM *
10519501SRobert.Johnston@Sun.COM * %% - literal % character
10529501SRobert.Johnston@Sun.COM * %s - base URL for knowledge articles
10539501SRobert.Johnston@Sun.COM * %<x> - expression x in the current event, if any
10549501SRobert.Johnston@Sun.COM *
10559501SRobert.Johnston@Sun.COM * If an invalid sequence is present, it is elided so we can safely
10569501SRobert.Johnston@Sun.COM * reserve any future characters for other types of expansions.
10579501SRobert.Johnston@Sun.COM */
10589501SRobert.Johnston@Sun.COM fmd_msg_buf_init(&buf);
10599501SRobert.Johnston@Sun.COM
10609501SRobert.Johnston@Sun.COM for (q = w, p = w; (p = wcschr(p, L'%')) != NULL; q = p) {
10619501SRobert.Johnston@Sun.COM if (p > q)
10629501SRobert.Johnston@Sun.COM fmd_msg_buf_write(&buf, q, (size_t)(p - q));
10639501SRobert.Johnston@Sun.COM
10649501SRobert.Johnston@Sun.COM switch (p[1]) {
10659501SRobert.Johnston@Sun.COM case L'%':
10669501SRobert.Johnston@Sun.COM fmd_msg_buf_write(&buf, p, 1);
10679501SRobert.Johnston@Sun.COM p += 2;
10689501SRobert.Johnston@Sun.COM break;
10699501SRobert.Johnston@Sun.COM
10709501SRobert.Johnston@Sun.COM case L's':
10719501SRobert.Johnston@Sun.COM fmd_msg_buf_write(&buf, u, wcslen(u));
10729501SRobert.Johnston@Sun.COM fmd_msg_buf_write(&buf, c, wcslen(c));
10739501SRobert.Johnston@Sun.COM
10749501SRobert.Johnston@Sun.COM p += 2;
10759501SRobert.Johnston@Sun.COM break;
10769501SRobert.Johnston@Sun.COM
10779501SRobert.Johnston@Sun.COM case L'<':
10789501SRobert.Johnston@Sun.COM q = p + 2;
10799501SRobert.Johnston@Sun.COM p = wcschr(p + 2, L'>');
10809501SRobert.Johnston@Sun.COM
10819501SRobert.Johnston@Sun.COM if (p == NULL)
10829501SRobert.Johnston@Sun.COM goto eos;
10839501SRobert.Johnston@Sun.COM
10849501SRobert.Johnston@Sun.COM /*
10859501SRobert.Johnston@Sun.COM * The expression in %< > must be an ASCII string: as
10869501SRobert.Johnston@Sun.COM * such allocate its length in bytes plus an extra
10879501SRobert.Johnston@Sun.COM * MB_CUR_MAX for slop if a multi-byte character is in
10889501SRobert.Johnston@Sun.COM * there, plus another byte for \0. Since we move a
10899501SRobert.Johnston@Sun.COM * byte at a time, any multi-byte chars will just be
10909501SRobert.Johnston@Sun.COM * silently overwritten and fail to parse, which is ok.
10919501SRobert.Johnston@Sun.COM */
10929501SRobert.Johnston@Sun.COM elen = (size_t)(p - q);
10939501SRobert.Johnston@Sun.COM expr = malloc(elen + MB_CUR_MAX + 1);
10949501SRobert.Johnston@Sun.COM
10959501SRobert.Johnston@Sun.COM if (expr == NULL) {
10969501SRobert.Johnston@Sun.COM buf.fmb_error = ENOMEM;
10979501SRobert.Johnston@Sun.COM goto eos;
10989501SRobert.Johnston@Sun.COM }
10999501SRobert.Johnston@Sun.COM
11009501SRobert.Johnston@Sun.COM for (i = 0; i < elen; i++)
11019501SRobert.Johnston@Sun.COM (void) wctomb(&expr[i], q[i]);
11029501SRobert.Johnston@Sun.COM
11039501SRobert.Johnston@Sun.COM expr[i] = '\0';
11049501SRobert.Johnston@Sun.COM
11059501SRobert.Johnston@Sun.COM if (nvl != NULL)
11069501SRobert.Johnston@Sun.COM (void) fmd_msg_nv_parse_nvname(&buf, nvl, expr);
11079501SRobert.Johnston@Sun.COM else
11089501SRobert.Johnston@Sun.COM fmd_msg_buf_printf(&buf, "%%<%s>", expr);
11099501SRobert.Johnston@Sun.COM
11109501SRobert.Johnston@Sun.COM free(expr);
11119501SRobert.Johnston@Sun.COM p++;
11129501SRobert.Johnston@Sun.COM break;
11139501SRobert.Johnston@Sun.COM
11149501SRobert.Johnston@Sun.COM case L'\0':
11159501SRobert.Johnston@Sun.COM goto eos;
11169501SRobert.Johnston@Sun.COM
11179501SRobert.Johnston@Sun.COM default:
11189501SRobert.Johnston@Sun.COM p += 2;
11199501SRobert.Johnston@Sun.COM break;
11209501SRobert.Johnston@Sun.COM }
11219501SRobert.Johnston@Sun.COM }
11229501SRobert.Johnston@Sun.COM eos:
11239501SRobert.Johnston@Sun.COM fmd_msg_buf_write(&buf, q, wcslen(q) + 1);
11249501SRobert.Johnston@Sun.COM
11259501SRobert.Johnston@Sun.COM free(c);
11269501SRobert.Johnston@Sun.COM free(u);
11279501SRobert.Johnston@Sun.COM free(w);
11289501SRobert.Johnston@Sun.COM
11299501SRobert.Johnston@Sun.COM s = fmd_msg_buf_read(&buf);
11309501SRobert.Johnston@Sun.COM fmd_msg_buf_fini(&buf);
11319501SRobert.Johnston@Sun.COM
11329501SRobert.Johnston@Sun.COM return (s);
11339501SRobert.Johnston@Sun.COM }
11349501SRobert.Johnston@Sun.COM
11359501SRobert.Johnston@Sun.COM /*
113612967Sgavin.maltby@oracle.com * This is a private interface used by the notification daemons to parse tokens
113712967Sgavin.maltby@oracle.com * in user-supplied message templates.
113812967Sgavin.maltby@oracle.com */
113912967Sgavin.maltby@oracle.com char *
fmd_msg_decode_tokens(nvlist_t * nvl,const char * msg,const char * url)114012967Sgavin.maltby@oracle.com fmd_msg_decode_tokens(nvlist_t *nvl, const char *msg, const char *url)
114112967Sgavin.maltby@oracle.com {
114212967Sgavin.maltby@oracle.com fmd_msg_buf_t buf;
114312967Sgavin.maltby@oracle.com wchar_t *h, *u, *w, *p, *q;
114412967Sgavin.maltby@oracle.com
114512967Sgavin.maltby@oracle.com char *s, *expr, host[MAXHOSTNAMELEN + 1];
114612967Sgavin.maltby@oracle.com size_t elen;
114712967Sgavin.maltby@oracle.com int i;
114812967Sgavin.maltby@oracle.com
114912967Sgavin.maltby@oracle.com u = fmd_msg_mbstowcs(url);
115012967Sgavin.maltby@oracle.com
115112967Sgavin.maltby@oracle.com (void) gethostname(host, MAXHOSTNAMELEN + 1);
115212967Sgavin.maltby@oracle.com h = fmd_msg_mbstowcs(host);
115312967Sgavin.maltby@oracle.com
115412967Sgavin.maltby@oracle.com if ((w = fmd_msg_mbstowcs(msg)) == NULL)
115512967Sgavin.maltby@oracle.com return (NULL);
115612967Sgavin.maltby@oracle.com
115712967Sgavin.maltby@oracle.com /*
115812967Sgavin.maltby@oracle.com * Now expand any escape sequences in the string, storing the final
115912967Sgavin.maltby@oracle.com * text in 'buf' in wide-character format, and then convert it back
116012967Sgavin.maltby@oracle.com * to multi-byte for return. We expand the following sequences:
116112967Sgavin.maltby@oracle.com *
116212967Sgavin.maltby@oracle.com * %% - literal % character
116312967Sgavin.maltby@oracle.com * %h - hostname
116412967Sgavin.maltby@oracle.com * %s - base URL for knowledge articles
116512967Sgavin.maltby@oracle.com * %<x> - expression x in the current event, if any
116612967Sgavin.maltby@oracle.com *
116712967Sgavin.maltby@oracle.com * If an invalid sequence is present, it is elided so we can safely
116812967Sgavin.maltby@oracle.com * reserve any future characters for other types of expansions.
116912967Sgavin.maltby@oracle.com */
117012967Sgavin.maltby@oracle.com fmd_msg_buf_init(&buf);
117112967Sgavin.maltby@oracle.com
117212967Sgavin.maltby@oracle.com for (q = w, p = w; (p = wcschr(p, L'%')) != NULL; q = p) {
117312967Sgavin.maltby@oracle.com if (p > q)
117412967Sgavin.maltby@oracle.com fmd_msg_buf_write(&buf, q, (size_t)(p - q));
117512967Sgavin.maltby@oracle.com
117612967Sgavin.maltby@oracle.com switch (p[1]) {
117712967Sgavin.maltby@oracle.com case L'%':
117812967Sgavin.maltby@oracle.com fmd_msg_buf_write(&buf, p, 1);
117912967Sgavin.maltby@oracle.com p += 2;
118012967Sgavin.maltby@oracle.com break;
118112967Sgavin.maltby@oracle.com
118212967Sgavin.maltby@oracle.com case L'h':
118312967Sgavin.maltby@oracle.com if (h != NULL)
118412967Sgavin.maltby@oracle.com fmd_msg_buf_write(&buf, h, wcslen(h));
118512967Sgavin.maltby@oracle.com
118612967Sgavin.maltby@oracle.com p += 2;
118712967Sgavin.maltby@oracle.com break;
118812967Sgavin.maltby@oracle.com
118912967Sgavin.maltby@oracle.com case L's':
119012967Sgavin.maltby@oracle.com if (u != NULL)
119112967Sgavin.maltby@oracle.com fmd_msg_buf_write(&buf, u, wcslen(u));
119212967Sgavin.maltby@oracle.com
119312967Sgavin.maltby@oracle.com p += 2;
119412967Sgavin.maltby@oracle.com break;
119512967Sgavin.maltby@oracle.com
119612967Sgavin.maltby@oracle.com case L'<':
119712967Sgavin.maltby@oracle.com q = p + 2;
119812967Sgavin.maltby@oracle.com p = wcschr(p + 2, L'>');
119912967Sgavin.maltby@oracle.com
120012967Sgavin.maltby@oracle.com if (p == NULL)
120112967Sgavin.maltby@oracle.com goto eos;
120212967Sgavin.maltby@oracle.com
120312967Sgavin.maltby@oracle.com /*
120412967Sgavin.maltby@oracle.com * The expression in %< > must be an ASCII string: as
120512967Sgavin.maltby@oracle.com * such allocate its length in bytes plus an extra
120612967Sgavin.maltby@oracle.com * MB_CUR_MAX for slop if a multi-byte character is in
120712967Sgavin.maltby@oracle.com * there, plus another byte for \0. Since we move a
120812967Sgavin.maltby@oracle.com * byte at a time, any multi-byte chars will just be
120912967Sgavin.maltby@oracle.com * silently overwritten and fail to parse, which is ok.
121012967Sgavin.maltby@oracle.com */
121112967Sgavin.maltby@oracle.com elen = (size_t)(p - q);
121212967Sgavin.maltby@oracle.com expr = malloc(elen + MB_CUR_MAX + 1);
121312967Sgavin.maltby@oracle.com
121412967Sgavin.maltby@oracle.com if (expr == NULL) {
121512967Sgavin.maltby@oracle.com buf.fmb_error = ENOMEM;
121612967Sgavin.maltby@oracle.com goto eos;
121712967Sgavin.maltby@oracle.com }
121812967Sgavin.maltby@oracle.com
121912967Sgavin.maltby@oracle.com for (i = 0; i < elen; i++)
122012967Sgavin.maltby@oracle.com (void) wctomb(&expr[i], q[i]);
122112967Sgavin.maltby@oracle.com
122212967Sgavin.maltby@oracle.com expr[i] = '\0';
122312967Sgavin.maltby@oracle.com
122412967Sgavin.maltby@oracle.com if (nvl != NULL)
122512967Sgavin.maltby@oracle.com (void) fmd_msg_nv_parse_nvname(&buf, nvl, expr);
122612967Sgavin.maltby@oracle.com else
122712967Sgavin.maltby@oracle.com fmd_msg_buf_printf(&buf, "%%<%s>", expr);
122812967Sgavin.maltby@oracle.com
122912967Sgavin.maltby@oracle.com free(expr);
123012967Sgavin.maltby@oracle.com p++;
123112967Sgavin.maltby@oracle.com break;
123212967Sgavin.maltby@oracle.com
123312967Sgavin.maltby@oracle.com case L'\0':
123412967Sgavin.maltby@oracle.com goto eos;
123512967Sgavin.maltby@oracle.com
123612967Sgavin.maltby@oracle.com default:
123712967Sgavin.maltby@oracle.com p += 2;
123812967Sgavin.maltby@oracle.com break;
123912967Sgavin.maltby@oracle.com }
124012967Sgavin.maltby@oracle.com }
124112967Sgavin.maltby@oracle.com eos:
124212967Sgavin.maltby@oracle.com fmd_msg_buf_write(&buf, q, wcslen(q) + 1);
124312967Sgavin.maltby@oracle.com
124412967Sgavin.maltby@oracle.com free(h);
124512967Sgavin.maltby@oracle.com free(u);
124612967Sgavin.maltby@oracle.com free(w);
124712967Sgavin.maltby@oracle.com
124812967Sgavin.maltby@oracle.com s = fmd_msg_buf_read(&buf);
124912967Sgavin.maltby@oracle.com fmd_msg_buf_fini(&buf);
125012967Sgavin.maltby@oracle.com
125112967Sgavin.maltby@oracle.com return (s);
125212967Sgavin.maltby@oracle.com }
125312967Sgavin.maltby@oracle.com
125412967Sgavin.maltby@oracle.com /*
12559501SRobert.Johnston@Sun.COM * This function is the main engine for formatting an entire event message.
12569501SRobert.Johnston@Sun.COM * It retrieves the master format string for an event, formats the individual
12579501SRobert.Johnston@Sun.COM * items, and then produces the final string composing all of the items. The
12589501SRobert.Johnston@Sun.COM * result is a newly-allocated multi-byte string of the localized message
12599501SRobert.Johnston@Sun.COM * text, or NULL with errno set if an error occurred.
12609501SRobert.Johnston@Sun.COM */
12619501SRobert.Johnston@Sun.COM static char *
fmd_msg_gettext_locked(fmd_msg_hdl_t * h,nvlist_t * nvl,const char * dict,const char * code)12629501SRobert.Johnston@Sun.COM fmd_msg_gettext_locked(fmd_msg_hdl_t *h,
12639501SRobert.Johnston@Sun.COM nvlist_t *nvl, const char *dict, const char *code)
12649501SRobert.Johnston@Sun.COM {
12659501SRobert.Johnston@Sun.COM char *items[FMD_MSG_ITEM_MAX];
12669501SRobert.Johnston@Sun.COM const char *format;
12679501SRobert.Johnston@Sun.COM char *buf = NULL;
12689501SRobert.Johnston@Sun.COM size_t len;
12699501SRobert.Johnston@Sun.COM int i;
12709501SRobert.Johnston@Sun.COM
12719501SRobert.Johnston@Sun.COM nvlist_t *fmri, *auth;
12729501SRobert.Johnston@Sun.COM struct tm tm, *tmp;
12739501SRobert.Johnston@Sun.COM
12749501SRobert.Johnston@Sun.COM int64_t *tv;
12759501SRobert.Johnston@Sun.COM uint_t tn = 0;
12769501SRobert.Johnston@Sun.COM time_t sec;
12779501SRobert.Johnston@Sun.COM char date[64];
12789501SRobert.Johnston@Sun.COM
12799501SRobert.Johnston@Sun.COM char *uuid, *src_name, *src_vers;
128010462SSean.Ye@Sun.COM char *platform, *server, *csn;
12819501SRobert.Johnston@Sun.COM
12829501SRobert.Johnston@Sun.COM assert(fmd_msg_lock_held(h));
12839501SRobert.Johnston@Sun.COM bzero(items, sizeof (items));
12849501SRobert.Johnston@Sun.COM
12859501SRobert.Johnston@Sun.COM for (i = 0; i < FMD_MSG_ITEM_MAX; i++) {
12869501SRobert.Johnston@Sun.COM items[i] = fmd_msg_getitem_locked(h, nvl, dict, code, i);
12879501SRobert.Johnston@Sun.COM if (items[i] == NULL)
12889501SRobert.Johnston@Sun.COM goto out;
12899501SRobert.Johnston@Sun.COM }
12909501SRobert.Johnston@Sun.COM
12919501SRobert.Johnston@Sun.COM /*
12929501SRobert.Johnston@Sun.COM * If <dict>.mo defines an item with the key <FMD_MSG_TEMPLATE> then it
12939501SRobert.Johnston@Sun.COM * is used as the format; otherwise the default from FMD.mo is used.
12949501SRobert.Johnston@Sun.COM */
12959501SRobert.Johnston@Sun.COM if ((format = dgettext(dict, FMD_MSG_TEMPLATE)) == FMD_MSG_TEMPLATE)
12969501SRobert.Johnston@Sun.COM format = h->fmh_template;
12979501SRobert.Johnston@Sun.COM
12989501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0)
12999501SRobert.Johnston@Sun.COM uuid = (char *)FMD_MSG_MISSING;
13009501SRobert.Johnston@Sun.COM
13019501SRobert.Johnston@Sun.COM if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME,
13029501SRobert.Johnston@Sun.COM &tv, &tn) == 0 && tn == 2 && (sec = (time_t)tv[0]) != (time_t)-1 &&
13039501SRobert.Johnston@Sun.COM (tmp = localtime_r(&sec, &tm)) != NULL)
130412967Sgavin.maltby@oracle.com (void) strftime(date, sizeof (date), "%a %b %e %H:%M:%S %Z %Y",
130512967Sgavin.maltby@oracle.com tmp);
13069501SRobert.Johnston@Sun.COM else
13079501SRobert.Johnston@Sun.COM (void) strlcpy(date, FMD_MSG_MISSING, sizeof (date));
13089501SRobert.Johnston@Sun.COM
13099501SRobert.Johnston@Sun.COM /*
13109501SRobert.Johnston@Sun.COM * Extract the relevant identifying elements of the FMRI and authority.
13119501SRobert.Johnston@Sun.COM * Note: for now, we ignore FM_FMRI_AUTH_DOMAIN (only for SPs).
13129501SRobert.Johnston@Sun.COM */
13139501SRobert.Johnston@Sun.COM if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) != 0)
13149501SRobert.Johnston@Sun.COM fmri = NULL;
13159501SRobert.Johnston@Sun.COM
13169501SRobert.Johnston@Sun.COM if (nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) != 0)
13179501SRobert.Johnston@Sun.COM auth = NULL;
13189501SRobert.Johnston@Sun.COM
13199501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(fmri, FM_FMRI_FMD_NAME, &src_name) != 0)
13209501SRobert.Johnston@Sun.COM src_name = (char *)FMD_MSG_MISSING;
13219501SRobert.Johnston@Sun.COM
13229501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(fmri, FM_FMRI_FMD_VERSION, &src_vers) != 0)
13239501SRobert.Johnston@Sun.COM src_vers = (char *)FMD_MSG_MISSING;
13249501SRobert.Johnston@Sun.COM
13259501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &platform) != 0)
13269501SRobert.Johnston@Sun.COM platform = (char *)FMD_MSG_MISSING;
13279501SRobert.Johnston@Sun.COM
13289501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) != 0)
13299501SRobert.Johnston@Sun.COM server = (char *)FMD_MSG_MISSING;
13309501SRobert.Johnston@Sun.COM
133110462SSean.Ye@Sun.COM if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &csn) != 0 &&
133210462SSean.Ye@Sun.COM nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) != 0)
133310462SSean.Ye@Sun.COM csn = (char *)FMD_MSG_MISSING;
13349501SRobert.Johnston@Sun.COM
13359501SRobert.Johnston@Sun.COM /*
13369501SRobert.Johnston@Sun.COM * Format the message once to get its length, allocate a buffer, and
13379501SRobert.Johnston@Sun.COM * then format the message again into the buffer to return it.
13389501SRobert.Johnston@Sun.COM */
13399501SRobert.Johnston@Sun.COM len = snprintf(NULL, 0, format, code,
13409501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_TYPE], items[FMD_MSG_ITEM_SEVERITY],
134110462SSean.Ye@Sun.COM date, platform, csn, server, src_name, src_vers, uuid,
13429501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_DESC], items[FMD_MSG_ITEM_RESPONSE],
13439501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_IMPACT], items[FMD_MSG_ITEM_ACTION]);
13449501SRobert.Johnston@Sun.COM
13459501SRobert.Johnston@Sun.COM if ((buf = malloc(len + 1)) == NULL) {
13469501SRobert.Johnston@Sun.COM errno = ENOMEM;
13479501SRobert.Johnston@Sun.COM goto out;
13489501SRobert.Johnston@Sun.COM }
13499501SRobert.Johnston@Sun.COM
13509501SRobert.Johnston@Sun.COM (void) snprintf(buf, len + 1, format, code,
13519501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_TYPE], items[FMD_MSG_ITEM_SEVERITY],
135210462SSean.Ye@Sun.COM date, platform, csn, server, src_name, src_vers, uuid,
13539501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_DESC], items[FMD_MSG_ITEM_RESPONSE],
13549501SRobert.Johnston@Sun.COM items[FMD_MSG_ITEM_IMPACT], items[FMD_MSG_ITEM_ACTION]);
13559501SRobert.Johnston@Sun.COM out:
13569501SRobert.Johnston@Sun.COM for (i = 0; i < FMD_MSG_ITEM_MAX; i++)
13579501SRobert.Johnston@Sun.COM free(items[i]);
13589501SRobert.Johnston@Sun.COM
13599501SRobert.Johnston@Sun.COM return (buf);
13609501SRobert.Johnston@Sun.COM }
13619501SRobert.Johnston@Sun.COM
13629501SRobert.Johnston@Sun.COM /*
13639501SRobert.Johnston@Sun.COM * Common code for fmd_msg_getitem_nv() and fmd_msg_getitem_id(): this function
13649501SRobert.Johnston@Sun.COM * handles locking, changing locales and domains, and restoring i18n state.
13659501SRobert.Johnston@Sun.COM */
13669501SRobert.Johnston@Sun.COM static char *
fmd_msg_getitem(fmd_msg_hdl_t * h,const char * locale,nvlist_t * nvl,const char * code,fmd_msg_item_t item)13679501SRobert.Johnston@Sun.COM fmd_msg_getitem(fmd_msg_hdl_t *h,
13689501SRobert.Johnston@Sun.COM const char *locale, nvlist_t *nvl, const char *code, fmd_msg_item_t item)
13699501SRobert.Johnston@Sun.COM {
13709501SRobert.Johnston@Sun.COM char *old_b, *old_c;
13719501SRobert.Johnston@Sun.COM char *dict, *key, *p, *s;
13729501SRobert.Johnston@Sun.COM size_t len;
13739501SRobert.Johnston@Sun.COM int err;
13749501SRobert.Johnston@Sun.COM
13759501SRobert.Johnston@Sun.COM if ((p = strchr(code, '-')) == NULL || p == code) {
13769501SRobert.Johnston@Sun.COM errno = EINVAL;
13779501SRobert.Johnston@Sun.COM return (NULL);
13789501SRobert.Johnston@Sun.COM }
13799501SRobert.Johnston@Sun.COM
13809501SRobert.Johnston@Sun.COM if (locale != NULL && strcmp(h->fmh_locale, locale) == 0)
13819501SRobert.Johnston@Sun.COM locale = NULL; /* simplify later tests */
13829501SRobert.Johnston@Sun.COM
1383*13093SRoger.Faulkner@Oracle.COM dict = strndupa(code, p - code);
13849501SRobert.Johnston@Sun.COM
13859501SRobert.Johnston@Sun.COM fmd_msg_lock();
13869501SRobert.Johnston@Sun.COM
13879501SRobert.Johnston@Sun.COM /*
13889501SRobert.Johnston@Sun.COM * If a non-default text domain binding was requested, save the old
13899501SRobert.Johnston@Sun.COM * binding perform the re-bind now that fmd_msg_lock() is held.
13909501SRobert.Johnston@Sun.COM */
13919501SRobert.Johnston@Sun.COM if (h->fmh_binding != NULL) {
13929501SRobert.Johnston@Sun.COM p = bindtextdomain(dict, NULL);
1393*13093SRoger.Faulkner@Oracle.COM old_b = strdupa(p);
13949501SRobert.Johnston@Sun.COM (void) bindtextdomain(dict, h->fmh_binding);
13959501SRobert.Johnston@Sun.COM }
13969501SRobert.Johnston@Sun.COM
13979501SRobert.Johnston@Sun.COM /*
13989501SRobert.Johnston@Sun.COM * Compute the lookup code for FMD_MSG_ITEM_TYPE: we'll use this to
13999501SRobert.Johnston@Sun.COM * determine if the dictionary contains any data for this code at all.
14009501SRobert.Johnston@Sun.COM */
14019501SRobert.Johnston@Sun.COM len = strlen(code) + 1 + strlen(fmd_msg_items[FMD_MSG_ITEM_TYPE]) + 1;
14029501SRobert.Johnston@Sun.COM key = alloca(len);
14039501SRobert.Johnston@Sun.COM
14049501SRobert.Johnston@Sun.COM (void) snprintf(key, len, "%s.%s",
14059501SRobert.Johnston@Sun.COM code, fmd_msg_items[FMD_MSG_ITEM_TYPE]);
14069501SRobert.Johnston@Sun.COM
14079501SRobert.Johnston@Sun.COM /*
14089501SRobert.Johnston@Sun.COM * Save the current locale string, and if we've been asked to fetch
14099501SRobert.Johnston@Sun.COM * the text for a different locale, switch locales now under the lock.
14109501SRobert.Johnston@Sun.COM */
14119501SRobert.Johnston@Sun.COM p = setlocale(LC_ALL, NULL);
1412*13093SRoger.Faulkner@Oracle.COM old_c = strdupa(p);
14139501SRobert.Johnston@Sun.COM
14149501SRobert.Johnston@Sun.COM if (locale != NULL)
14159501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, locale);
14169501SRobert.Johnston@Sun.COM
14179501SRobert.Johnston@Sun.COM /*
14189501SRobert.Johnston@Sun.COM * Prefetch the first item: if this isn't found, and we're in a non-
14199501SRobert.Johnston@Sun.COM * default locale, attempt to fall back to the C locale for this code.
14209501SRobert.Johnston@Sun.COM */
14219501SRobert.Johnston@Sun.COM if (dgettext(dict, key) == key &&
14229501SRobert.Johnston@Sun.COM (locale != NULL || strcmp(h->fmh_locale, "C") != 0)) {
14239501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, "C");
14249501SRobert.Johnston@Sun.COM locale = "C"; /* restore locale */
14259501SRobert.Johnston@Sun.COM }
14269501SRobert.Johnston@Sun.COM
14279501SRobert.Johnston@Sun.COM if (dgettext(dict, key) == key) {
14289501SRobert.Johnston@Sun.COM s = NULL;
14299501SRobert.Johnston@Sun.COM err = ENOENT;
14309501SRobert.Johnston@Sun.COM } else {
14319501SRobert.Johnston@Sun.COM s = fmd_msg_getitem_locked(h, nvl, dict, code, item);
14329501SRobert.Johnston@Sun.COM err = errno;
14339501SRobert.Johnston@Sun.COM }
14349501SRobert.Johnston@Sun.COM
14359501SRobert.Johnston@Sun.COM if (locale != NULL)
14369501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, old_c);
14379501SRobert.Johnston@Sun.COM
14389501SRobert.Johnston@Sun.COM if (h->fmh_binding != NULL)
14399501SRobert.Johnston@Sun.COM (void) bindtextdomain(dict, old_b);
14409501SRobert.Johnston@Sun.COM
14419501SRobert.Johnston@Sun.COM fmd_msg_unlock();
14429501SRobert.Johnston@Sun.COM
14439501SRobert.Johnston@Sun.COM if (s == NULL)
14449501SRobert.Johnston@Sun.COM errno = err;
14459501SRobert.Johnston@Sun.COM
14469501SRobert.Johnston@Sun.COM return (s);
14479501SRobert.Johnston@Sun.COM }
14489501SRobert.Johnston@Sun.COM
14499501SRobert.Johnston@Sun.COM char *
fmd_msg_getitem_nv(fmd_msg_hdl_t * h,const char * locale,nvlist_t * nvl,fmd_msg_item_t item)14509501SRobert.Johnston@Sun.COM fmd_msg_getitem_nv(fmd_msg_hdl_t *h,
14519501SRobert.Johnston@Sun.COM const char *locale, nvlist_t *nvl, fmd_msg_item_t item)
14529501SRobert.Johnston@Sun.COM {
14539501SRobert.Johnston@Sun.COM char *code;
14549501SRobert.Johnston@Sun.COM
14559501SRobert.Johnston@Sun.COM if (item >= FMD_MSG_ITEM_MAX) {
14569501SRobert.Johnston@Sun.COM errno = EINVAL;
14579501SRobert.Johnston@Sun.COM return (NULL);
14589501SRobert.Johnston@Sun.COM }
14599501SRobert.Johnston@Sun.COM
14609501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code) != 0) {
14619501SRobert.Johnston@Sun.COM errno = EINVAL;
14629501SRobert.Johnston@Sun.COM return (NULL);
14639501SRobert.Johnston@Sun.COM }
14649501SRobert.Johnston@Sun.COM
14659501SRobert.Johnston@Sun.COM return (fmd_msg_getitem(h, locale, nvl, code, item));
14669501SRobert.Johnston@Sun.COM }
14679501SRobert.Johnston@Sun.COM
14689501SRobert.Johnston@Sun.COM char *
fmd_msg_getitem_id(fmd_msg_hdl_t * h,const char * locale,const char * code,fmd_msg_item_t item)14699501SRobert.Johnston@Sun.COM fmd_msg_getitem_id(fmd_msg_hdl_t *h,
14709501SRobert.Johnston@Sun.COM const char *locale, const char *code, fmd_msg_item_t item)
14719501SRobert.Johnston@Sun.COM {
14729501SRobert.Johnston@Sun.COM if (item >= FMD_MSG_ITEM_MAX) {
14739501SRobert.Johnston@Sun.COM errno = EINVAL;
14749501SRobert.Johnston@Sun.COM return (NULL);
14759501SRobert.Johnston@Sun.COM }
14769501SRobert.Johnston@Sun.COM
14779501SRobert.Johnston@Sun.COM return (fmd_msg_getitem(h, locale, NULL, code, item));
14789501SRobert.Johnston@Sun.COM }
14799501SRobert.Johnston@Sun.COM
148012967Sgavin.maltby@oracle.com char *
fmd_msg_gettext_key(fmd_msg_hdl_t * h,const char * locale,const char * dict,const char * key)148112967Sgavin.maltby@oracle.com fmd_msg_gettext_key(fmd_msg_hdl_t *h,
148212967Sgavin.maltby@oracle.com const char *locale, const char *dict, const char *key)
148312967Sgavin.maltby@oracle.com {
148412967Sgavin.maltby@oracle.com char *old_b, *old_c, *p, *s;
148512967Sgavin.maltby@oracle.com
148612967Sgavin.maltby@oracle.com fmd_msg_lock();
148712967Sgavin.maltby@oracle.com
148812967Sgavin.maltby@oracle.com /*
148912967Sgavin.maltby@oracle.com * If a non-default text domain binding was requested, save the old
149012967Sgavin.maltby@oracle.com * binding perform the re-bind now that fmd_msg_lock() is held.
149112967Sgavin.maltby@oracle.com */
149212967Sgavin.maltby@oracle.com if (h->fmh_binding != NULL) {
149312967Sgavin.maltby@oracle.com p = bindtextdomain(dict, NULL);
149412967Sgavin.maltby@oracle.com old_b = alloca(strlen(p) + 1);
149512967Sgavin.maltby@oracle.com (void) strcpy(old_b, p);
149612967Sgavin.maltby@oracle.com (void) bindtextdomain(dict, h->fmh_binding);
149712967Sgavin.maltby@oracle.com }
149812967Sgavin.maltby@oracle.com
149912967Sgavin.maltby@oracle.com /*
150012967Sgavin.maltby@oracle.com * Save the current locale string, and if we've been asked to fetch
150112967Sgavin.maltby@oracle.com * the text for a different locale, switch locales now under the lock.
150212967Sgavin.maltby@oracle.com */
150312967Sgavin.maltby@oracle.com p = setlocale(LC_ALL, NULL);
150412967Sgavin.maltby@oracle.com old_c = alloca(strlen(p) + 1);
150512967Sgavin.maltby@oracle.com (void) strcpy(old_c, p);
150612967Sgavin.maltby@oracle.com
150712967Sgavin.maltby@oracle.com if (locale != NULL)
150812967Sgavin.maltby@oracle.com (void) setlocale(LC_ALL, locale);
150912967Sgavin.maltby@oracle.com
151012967Sgavin.maltby@oracle.com /*
151112967Sgavin.maltby@oracle.com * First attempt to fetch the string in the current locale. If this
151212967Sgavin.maltby@oracle.com * fails and we're in a non-default locale, attempt to fall back to the
151312967Sgavin.maltby@oracle.com * C locale and try again. If it still fails then we return NULL and
151412967Sgavin.maltby@oracle.com * set errno.
151512967Sgavin.maltby@oracle.com */
151612967Sgavin.maltby@oracle.com if ((s = dgettext(dict, key)) == key &&
151712967Sgavin.maltby@oracle.com (locale != NULL || strcmp(h->fmh_locale, "C") != 0)) {
151812967Sgavin.maltby@oracle.com (void) setlocale(LC_ALL, "C");
151912967Sgavin.maltby@oracle.com locale = "C"; /* restore locale */
152012967Sgavin.maltby@oracle.com
152112967Sgavin.maltby@oracle.com if ((s = dgettext(dict, key)) == key) {
152212967Sgavin.maltby@oracle.com s = NULL;
152312967Sgavin.maltby@oracle.com errno = ENOENT;
152412967Sgavin.maltby@oracle.com }
152512967Sgavin.maltby@oracle.com }
152612967Sgavin.maltby@oracle.com if (locale != NULL)
152712967Sgavin.maltby@oracle.com (void) setlocale(LC_ALL, old_c);
152812967Sgavin.maltby@oracle.com
152912967Sgavin.maltby@oracle.com if (h->fmh_binding != NULL)
153012967Sgavin.maltby@oracle.com (void) bindtextdomain(dict, old_b);
153112967Sgavin.maltby@oracle.com
153212967Sgavin.maltby@oracle.com fmd_msg_unlock();
153312967Sgavin.maltby@oracle.com
153412967Sgavin.maltby@oracle.com return (s);
153512967Sgavin.maltby@oracle.com }
153612967Sgavin.maltby@oracle.com
15379501SRobert.Johnston@Sun.COM /*
15389501SRobert.Johnston@Sun.COM * Common code for fmd_msg_gettext_nv() and fmd_msg_gettext_id(): this function
15399501SRobert.Johnston@Sun.COM * handles locking, changing locales and domains, and restoring i18n state.
15409501SRobert.Johnston@Sun.COM */
15419501SRobert.Johnston@Sun.COM static char *
fmd_msg_gettext(fmd_msg_hdl_t * h,const char * locale,nvlist_t * nvl,const char * code)15429501SRobert.Johnston@Sun.COM fmd_msg_gettext(fmd_msg_hdl_t *h,
15439501SRobert.Johnston@Sun.COM const char *locale, nvlist_t *nvl, const char *code)
15449501SRobert.Johnston@Sun.COM {
15459501SRobert.Johnston@Sun.COM char *old_b, *old_c;
15469501SRobert.Johnston@Sun.COM char *dict, *key, *p, *s;
15479501SRobert.Johnston@Sun.COM size_t len;
15489501SRobert.Johnston@Sun.COM int err;
15499501SRobert.Johnston@Sun.COM
15509501SRobert.Johnston@Sun.COM if ((p = strchr(code, '-')) == NULL || p == code) {
15519501SRobert.Johnston@Sun.COM errno = EINVAL;
15529501SRobert.Johnston@Sun.COM return (NULL);
15539501SRobert.Johnston@Sun.COM }
15549501SRobert.Johnston@Sun.COM
15559501SRobert.Johnston@Sun.COM if (locale != NULL && strcmp(h->fmh_locale, locale) == 0)
15569501SRobert.Johnston@Sun.COM locale = NULL; /* simplify later tests */
15579501SRobert.Johnston@Sun.COM
1558*13093SRoger.Faulkner@Oracle.COM dict = strndupa(code, p - code);
15599501SRobert.Johnston@Sun.COM
15609501SRobert.Johnston@Sun.COM fmd_msg_lock();
15619501SRobert.Johnston@Sun.COM
15629501SRobert.Johnston@Sun.COM /*
15639501SRobert.Johnston@Sun.COM * If a non-default text domain binding was requested, save the old
15649501SRobert.Johnston@Sun.COM * binding perform the re-bind now that fmd_msg_lock() is held.
15659501SRobert.Johnston@Sun.COM */
15669501SRobert.Johnston@Sun.COM if (h->fmh_binding != NULL) {
15679501SRobert.Johnston@Sun.COM p = bindtextdomain(dict, NULL);
1568*13093SRoger.Faulkner@Oracle.COM old_b = strdupa(p);
15699501SRobert.Johnston@Sun.COM (void) bindtextdomain(dict, h->fmh_binding);
15709501SRobert.Johnston@Sun.COM }
15719501SRobert.Johnston@Sun.COM
15729501SRobert.Johnston@Sun.COM /*
15739501SRobert.Johnston@Sun.COM * Compute the lookup code for FMD_MSG_ITEM_TYPE: we'll use this to
15749501SRobert.Johnston@Sun.COM * determine if the dictionary contains any data for this code at all.
15759501SRobert.Johnston@Sun.COM */
15769501SRobert.Johnston@Sun.COM len = strlen(code) + 1 + strlen(fmd_msg_items[FMD_MSG_ITEM_TYPE]) + 1;
15779501SRobert.Johnston@Sun.COM key = alloca(len);
15789501SRobert.Johnston@Sun.COM
15799501SRobert.Johnston@Sun.COM (void) snprintf(key, len, "%s.%s",
15809501SRobert.Johnston@Sun.COM code, fmd_msg_items[FMD_MSG_ITEM_TYPE]);
15819501SRobert.Johnston@Sun.COM
15829501SRobert.Johnston@Sun.COM /*
15839501SRobert.Johnston@Sun.COM * Save the current locale string, and if we've been asked to fetch
15849501SRobert.Johnston@Sun.COM * the text for a different locale, switch locales now under the lock.
15859501SRobert.Johnston@Sun.COM */
15869501SRobert.Johnston@Sun.COM p = setlocale(LC_ALL, NULL);
1587*13093SRoger.Faulkner@Oracle.COM old_c = strdupa(p);
15889501SRobert.Johnston@Sun.COM
15899501SRobert.Johnston@Sun.COM if (locale != NULL)
15909501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, locale);
15919501SRobert.Johnston@Sun.COM
15929501SRobert.Johnston@Sun.COM /*
15939501SRobert.Johnston@Sun.COM * Prefetch the first item: if this isn't found, and we're in a non-
15949501SRobert.Johnston@Sun.COM * default locale, attempt to fall back to the C locale for this code.
15959501SRobert.Johnston@Sun.COM */
15969501SRobert.Johnston@Sun.COM if (dgettext(dict, key) == key &&
15979501SRobert.Johnston@Sun.COM (locale != NULL || strcmp(h->fmh_locale, "C") != 0)) {
15989501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, "C");
15999501SRobert.Johnston@Sun.COM locale = "C"; /* restore locale */
16009501SRobert.Johnston@Sun.COM }
16019501SRobert.Johnston@Sun.COM
16029501SRobert.Johnston@Sun.COM if (dgettext(dict, key) == key) {
16039501SRobert.Johnston@Sun.COM s = NULL;
16049501SRobert.Johnston@Sun.COM err = ENOENT;
16059501SRobert.Johnston@Sun.COM } else {
16069501SRobert.Johnston@Sun.COM s = fmd_msg_gettext_locked(h, nvl, dict, code);
16079501SRobert.Johnston@Sun.COM err = errno;
16089501SRobert.Johnston@Sun.COM }
16099501SRobert.Johnston@Sun.COM
16109501SRobert.Johnston@Sun.COM if (locale != NULL)
16119501SRobert.Johnston@Sun.COM (void) setlocale(LC_ALL, old_c);
16129501SRobert.Johnston@Sun.COM
16139501SRobert.Johnston@Sun.COM if (h->fmh_binding != NULL)
16149501SRobert.Johnston@Sun.COM (void) bindtextdomain(dict, old_b);
16159501SRobert.Johnston@Sun.COM
16169501SRobert.Johnston@Sun.COM fmd_msg_unlock();
16179501SRobert.Johnston@Sun.COM
16189501SRobert.Johnston@Sun.COM if (s == NULL)
16199501SRobert.Johnston@Sun.COM errno = err;
16209501SRobert.Johnston@Sun.COM
16219501SRobert.Johnston@Sun.COM return (s);
16229501SRobert.Johnston@Sun.COM }
16239501SRobert.Johnston@Sun.COM
16249501SRobert.Johnston@Sun.COM char *
fmd_msg_gettext_nv(fmd_msg_hdl_t * h,const char * locale,nvlist_t * nvl)16259501SRobert.Johnston@Sun.COM fmd_msg_gettext_nv(fmd_msg_hdl_t *h, const char *locale, nvlist_t *nvl)
16269501SRobert.Johnston@Sun.COM {
16279501SRobert.Johnston@Sun.COM char *code;
16289501SRobert.Johnston@Sun.COM
16299501SRobert.Johnston@Sun.COM if (nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code) != 0) {
16309501SRobert.Johnston@Sun.COM errno = EINVAL;
16319501SRobert.Johnston@Sun.COM return (NULL);
16329501SRobert.Johnston@Sun.COM }
16339501SRobert.Johnston@Sun.COM
16349501SRobert.Johnston@Sun.COM return (fmd_msg_gettext(h, locale, nvl, code));
16359501SRobert.Johnston@Sun.COM }
16369501SRobert.Johnston@Sun.COM
16379501SRobert.Johnston@Sun.COM char *
fmd_msg_gettext_id(fmd_msg_hdl_t * h,const char * locale,const char * code)16389501SRobert.Johnston@Sun.COM fmd_msg_gettext_id(fmd_msg_hdl_t *h, const char *locale, const char *code)
16399501SRobert.Johnston@Sun.COM {
16409501SRobert.Johnston@Sun.COM return (fmd_msg_gettext(h, locale, NULL, code));
16419501SRobert.Johnston@Sun.COM }
1642