1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 2000 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * This file is a module that handles the logging features of the
31 * DCS. All error messages that are generated by the DCS are kept in
32 * a static array and accessed through one of the access functions
33 * defined in this file.
34 */
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <stdarg.h>
39#include <string.h>
40#include <errno.h>
41#include <assert.h>
42#include <syslog.h>
43#include <libintl.h>
44
45#include "dcs.h"
46
47
48#define	SYSLOG_FMT	"<%d> %s"
49
50
51/*
52 * This is an array of strings representing all of the error and
53 * informational messages that are used by the DCS. This includes
54 * messages that are logged using syslog(3C) and those that are
55 * displayed to the user through a message callback.
56 */
57static const char *dcs_err_fmt[] = {
58
59	/*
60	 * Network Errors:
61	 */
62	/* DCS_INIT_ERR	    */ "network initialization failed",
63	/* DCS_NO_PORT	    */ "failed to acquire reserved port",
64	/* DCS_CONNECT_ERR  */ "connection attempt failed",
65	/* DCS_RECEIVE_ERR  */ "unable to receive message",
66	/* DCS_OP_REPLY_ERR */ "unable to send message for %s operation",
67	/* DCS_NO_SERV	    */ "%s service not found, using reserved port 665",
68	/* DCS_DISCONNECT   */ "client disconnected",
69
70	/*
71	 * Session Errors:
72	 */
73	/* DCS_SES_HAND_ERR */ "failed to start a new session handler",
74	/* DCS_ABORT_ERR    */ "abort attempt of session, %d, unsuccessful",
75	/* DCS_VER_INVAL    */ "unsupported message protocol version %d.%d",
76	/* DCS_SES_ABORTED  */ "session aborted",
77
78	/*
79	 * DR Request Errors:
80	 */
81	/* DCS_UNKNOWN_OP   */ "unknown operation requested",
82	/* DCS_OP_FAILED    */ "operation failed",
83	/* DCS_SEQ_INVAL    */ "invalid session establishment sequence",
84	/* DCS_NO_SES_ESTBL */ "%s operation issued before session established",
85	/* DCS_MSG_INVAL    */ "received an invalid message",
86	/* DCS_CONF_CB_ERR  */ "confirm callback failed, aborting operation",
87	/* DCS_MSG_CB_ERR   */ "message callback failed, continuing",
88	/* DCS_BAD_RETRY    */ "retry value invalid (%d)",
89	/* DCS_BAD_TIMEOUT  */ "timeout value invalid (%d)",
90	/* DCS_RETRY	    */ "retrying operation, attempt %d",
91
92	/*
93	 * General Errors:
94	 */
95	/* DCS_NO_PRIV	    */ "permission denied",
96	/* DCS_INT_ERR	    */ "internal error: %s: %s",
97	/* DCS_UNKNOWN_ERR  */ "unrecognized error reported",
98	/* DCS_BAD_OPT	    */ "illegal option (-%c), exiting",
99	/* DCS_BAD_OPT_ARG  */ "illegal argument to -%c flag (%s), %s",
100	/* DCS_CFGA_UNKNOWN */ "configuration administration unknown error",
101	/* DCS_CFGA_ERR	    */ "%s: %s",
102	/* DCS_RSRC_ERR	    */ "resource info init error (%d)",
103	/* DCS_MSG_COUNT    */ NULL
104};
105
106
107/*
108 * dcs_log_msg:
109 *
110 * Based on an error code, construct an error string and output it to
111 * a logfile using syslog(3C). Note that the string will not be localized.
112 */
113void
114dcs_log_msg(int priority, int err_code, ...)
115{
116	va_list	vap;
117	char	err_str[MAX_MSG_LEN];
118	char	syslog_str[MAX_MSG_LEN];
119
120
121	/* check if error code is out of bounds */
122	if ((err_code < 0) || (err_code >= DCS_MSG_COUNT)) {
123		syslog(LOG_NOTICE, dcs_err_fmt[DCS_UNKNOWN_ERR]);
124		return;
125	}
126
127	va_start(vap, err_code);
128	(void) vsnprintf(err_str, MAX_MSG_LEN, dcs_err_fmt[err_code], vap);
129	va_end(vap);
130
131	/* prepend session identifier */
132	snprintf(syslog_str, MAX_MSG_LEN, SYSLOG_FMT, curr_ses_id(), err_str);
133
134	syslog(priority, syslog_str);
135
136	if (standalone) {
137		fprintf(stderr, "%s\n", syslog_str);
138	}
139}
140
141
142/*
143 * dcs_strerror:
144 *
145 * Return the format string associated with a supplied DCS specific
146 * error code. dgettext(3C) is used to retrieve the localized version
147 * of the format string.
148 */
149const char *
150dcs_strerror(int err_code)
151{
152	/* check if code is out of bounds */
153	if ((err_code < 0) || (err_code >= DCS_MSG_COUNT)) {
154		return (dgettext(TEXT_DOMAIN, dcs_err_fmt[DCS_UNKNOWN_ERR]));
155	}
156
157	return (dgettext(TEXT_DOMAIN, dcs_err_fmt[err_code]));
158}
159
160
161/*
162 * dcs_cfga_str:
163 *
164 * Assemble a string that describes a particular libcfgadm error code.
165 * This string will contain both the platform dependent and platform
166 * independent message strings available from a libcfgadm function call.
167 * The resulting string will be localized indirectly through the call
168 * to config_strerror() and the localized error string returned from
169 * the libcfgadm operation.
170 */
171char *
172dcs_cfga_str(char **err_strp, int err_code)
173{
174	const char	*ep;
175	char		*buf;
176	char		*err_str;
177
178
179	/*
180	 * Extract the platform specific message passed as
181	 * a parameter, or use NULL to signal that no error
182	 * string was passed.
183	 */
184	if (err_strp && *err_strp) {
185		err_str = *err_strp;
186	} else {
187		err_str = NULL;
188	}
189
190	buf = (char *)malloc(MAX_MSG_LEN);
191
192	if (buf == NULL) {
193		dcs_log_msg(LOG_ERR, DCS_INT_ERR, "malloc", strerror(errno));
194		return (NULL);
195	}
196
197	/* get the platform independent message */
198	ep = config_strerror(err_code);
199
200	if (ep == NULL) {
201		ep = dgettext(TEXT_DOMAIN, dcs_err_fmt[DCS_CFGA_UNKNOWN]);
202	}
203
204	/*
205	 * Check if a platform specific message was provided, and
206	 * generate the appropriate message.
207	 */
208	if ((err_str != NULL) && (*err_str != '\0')) {
209		snprintf(buf, MAX_MSG_LEN, "%s: %s\n", ep, err_str);
210	} else {
211		snprintf(buf, MAX_MSG_LEN, "%s\n", ep);
212	}
213
214	return (buf);
215}
216
217
218/*
219 * dcs_dbg:
220 *
221 * Output a debugging message to a logfile using syslog(3C). The bits
222 * in the debug mask specify the category of the message. They have
223 * the following meanings:
224 *
225 * 		0x1 - the string contains basic information
226 *		0x2 - the string contains message information
227 *		0x4 - the string contains session information
228 *		0x8 - the string contains state information
229 *
230 * The debug mask is compared to the global value of dcs_debug which is
231 * set through a command line option. This determines whether or not
232 * to output the message to the logfile.
233 */
234void
235dcs_dbg(int dbg_mask, char *fmt, ...)
236{
237	va_list		vap;
238	char		err_str[MAX_MSG_LEN];
239	char		syslog_str[MAX_MSG_LEN];
240
241
242	if ((dcs_debug & dbg_mask) == 0) {
243		return;
244	}
245
246	va_start(vap, fmt);
247	(void) vsnprintf(err_str, MAX_MSG_LEN, fmt, vap);
248	va_end(vap);
249
250	/* prepend session identifier */
251	snprintf(syslog_str, MAX_MSG_LEN, SYSLOG_FMT, curr_ses_id(), err_str);
252
253	syslog(LOG_DEBUG, syslog_str);
254
255	if (standalone) {
256		fprintf(stderr, "%s\n", syslog_str);
257	}
258}
259
260
261/*
262 * print_msg_hdr:
263 *
264 * Print selected information from the header for a given message. The
265 * information logged includes the information needed to track the flow
266 * of messages: opcode, send/receive, request/reply, and success/failure.
267 */
268void
269print_msg_hdr(dcs_msg_type_t type, rdr_msg_hdr_t *hdr)
270{
271	static char *type_str[] = {
272		"INVALID TYPE",
273		"RDR_REQUEST",
274		"RDR_REPLY"
275	};
276
277	static char *op_str[] = {
278		"RDR_INVALID_OP",
279		"RDR_SES_REQ",
280		"RDR_SES_ESTBL",
281		"RDR_SES_END",
282		"RDR_CONF_CHANGE_STATE",
283		"RDR_CONF_PRIVATE_FUNC",
284		"RDR_CONF_TEST",
285		"RDR_CONF_LIST_EXT",
286		"RDR_CONF_HELP",
287		"RDR_CONF_AP_ID_CMP",
288		"RDR_CONF_ABORT_CMD",
289		"RDR_CONF_CONFIRM_CALLBACK",
290		"RDR_CONF_MSG_CALLBACK",
291		"RDR_RSRC_INFO"
292	};
293
294	assert(hdr);
295
296	/* clamp an invalid opcode */
297	if (hdr->message_opcode >= RDR_NUM_OPS) {
298		hdr->message_opcode = 0;
299	}
300
301	/* clamp an invalid type */
302	if (hdr->data_type > RDR_REPLY) {
303		hdr->data_type = 0;
304	}
305
306	DCS_DBG(DBG_MSG, "message %s: <%s, %s%s>",
307	    (type == DCS_RECEIVE) ? "received" : "sent",
308	    op_str[hdr->message_opcode],
309	    type_str[hdr->data_type],
310	    ((hdr->data_type == RDR_REQUEST) ||
311	    (hdr->message_opcode == RDR_CONF_AP_ID_CMP)) ? "" :
312	    (hdr->status == RDR_SUCCESS) ? ", RDR_SUCCESS" :
313	    ", RDR_FAILED");
314}
315