Home | History | Annotate | Download | only in common
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <ctype.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <stdarg.h>
     32 #include <string.h>
     33 #include <unistd.h>
     34 #include <macros.h>
     35 #include <errno.h>
     36 #include <locale.h>
     37 #include <libdevinfo.h>
     38 #include <librcm.h>
     39 #define	CFGA_PLUGIN_LIB
     40 #include <config_admin.h>
     41 #include "ap.h"
     42 
     43 #ifdef	SBD_DEBUG
     44 
     45 static FILE *debug_fp;
     46 
     47 int
     48 debugging(void)
     49 {
     50 	char *ep;
     51 	static int inited;
     52 
     53 	if (inited)
     54 		return (debug_fp != NULL);
     55 	inited = 1;
     56 
     57 	if ((ep = getenv("SBD_DEBUG")) == NULL)
     58 		return (0);
     59 
     60 	if (*ep == '\0')
     61 		debug_fp = stderr;
     62 	else {
     63 		if ((debug_fp = fopen(ep, "a")) == NULL)
     64 			return (0);
     65 	}
     66 	(void) fprintf(debug_fp,
     67 		"\nDebug started, pid=%d\n", (int)getpid());
     68 	return (1);
     69 }
     70 
     71 /*PRINTFLIKE1*/
     72 void
     73 dbg(char *fmt, ...)
     74 {
     75 	va_list ap;
     76 
     77 	if (!debugging())
     78 		return;
     79 
     80 	va_start(ap, fmt);
     81 	(void) vfprintf(debug_fp, fmt, ap);
     82 	va_end(ap);
     83 }
     84 #endif
     85 
     86 static char *
     87 ap_err_fmts[] = {
     88 	"command invalid: %s",
     89 	"%s %s: %s%s%s",			/* command failed */
     90 	"%s %s",				/* command nacked */
     91 	"command not supported: %s %s",
     92 	"command aborted: %s %s",
     93 	"option invalid: %s",
     94 	"option requires value: %s",
     95 	"option requires no value: %s",
     96 	"option value invalid: %s %s",
     97 	"attachment point invalid: %s",
     98 	"component invalid: %s",
     99 	"sequence invalid: %s (%s %s) %s",
    100 	"change signal disposition failed",
    101 	"cannot get RCM handle",
    102 	"RCM %s failed for %s",
    103 	"\n%-30s %-10s %s",
    104 	"cannot open %s%s%s",
    105 	"cannot find symbol %s in %s",
    106 	"cannot stat %s: %s",
    107 	"not enough memory",
    108 	"%s plugin: %s",
    109 	"unknown error",
    110 	NULL
    111 };
    112 
    113 #define	ap_err_fmt(i)		ap_err_fmts[min((i), ERR_NONE)]
    114 
    115 static char *
    116 ap_msg_fmts[] = {
    117 	"%s %s\n",
    118 	"%s %s skipped\n",
    119 	"System may be temporarily suspended, proceed",
    120 	"%s %s aborted\n",
    121 	"%s %s done\n",
    122 	"%s %s failed\n",
    123 	"RCM library not found, feature will be disabled\n",
    124 	"Unknown message\n",
    125 	NULL
    126 };
    127 
    128 #define	ap_msg_fmt(i)		ap_msg_fmts[min((i), MSG_NONE)]
    129 
    130 #define	STR_BD			"board"
    131 #define	STR_SEP			": "
    132 #define	STR_NULL		"NULL"
    133 #define	STR_CMD_UNKNOWN		"unknown command"
    134 #define	STR_ERR_UNKNOWN		"unknown error"
    135 #define	STR_MSG_UNKNOWN		"unknown message\n"
    136 #define	STR_TGT_UNKNOWN		"unknown target"
    137 
    138 #define	get_cmd(c, ap, v) \
    139 { \
    140 	(v) = va_arg((ap), int); \
    141 	if (((c) = ap_cmd_name((v))) == NULL) \
    142 		(c) = STR_CMD_UNKNOWN; \
    143 }
    144 #define	get_tgt(t, ap) {\
    145 	(t) = va_arg((ap), char *); \
    146 	if (!str_valid((t))) \
    147 		(t) = STR_TGT_UNKNOWN; \
    148 }
    149 #define	check_tgt(tgt, t) {\
    150 	if (str_valid((tgt))) \
    151 		(t) = (tgt); \
    152 	else \
    153 		(t) = STR_TGT_UNKNOWN; \
    154 }
    155 #define	get_str(v, ap, d) \
    156 { \
    157 	(v) = va_arg((ap), char *); \
    158 	if ((v) == NULL) \
    159 		(v) = (d); \
    160 }
    161 
    162 static char *
    163 ap_stnames[] = {
    164 	"unknown state",
    165 	"empty",
    166 	"disconnected",
    167 	"connected",
    168 	"unconfigured",
    169 	"configured"
    170 };
    171 
    172 /*
    173  * ap_err() accepts a variable number of message IDs and constructs
    174  * a corresponding error string.  ap_err() calls dgettext() to
    175  * internationalize the proper portions of a message.  If a system
    176  * error was encountered (errno set), ap_err() looks for the error
    177  * string corresponding to the returned error code if one is available.
    178  * If not, the standard libc error string is fetched.
    179  */
    180 void
    181 ap_err(apd_t *a, ...)
    182 {
    183 	int v;
    184 	int err;
    185 	int len;
    186 	char *p;
    187 	char *sep;
    188 	char *rsep;
    189 	const char *fmt;
    190 	char *cmd;
    191 	char *value;
    192 	char *target;
    193 	char *serr;
    194 	char *syserr;
    195 	char *rstate;
    196 	char *ostate;
    197 	char *srsrc;
    198 	char *sysrsrc;
    199 	char *option;
    200 	char *path;
    201 	char *sym;
    202 	char *msg;
    203 	const char *error;
    204 	char **errstring;
    205 	char *rinfostr = NULL;
    206 	va_list ap;
    207 
    208 	DBG("ap_err(%p)\n", (void *)a);
    209 
    210 	/*
    211 	 * If there is no descriptor or string pointer or if
    212 	 * there is an outstanding error, just return.
    213 	 */
    214 	if (a == NULL || (errstring = a->errstring) == NULL ||
    215 	    *errstring != NULL)
    216 		return;
    217 
    218 	va_start(ap, a);
    219 
    220 	err = va_arg(ap, int);
    221 
    222 	if ((fmt = ap_err_fmt(err)) == NULL)
    223 		fmt = STR_ERR_UNKNOWN;
    224 	fmt = dgettext(TEXT_DOMAIN, fmt);
    225 	len = strlen(fmt);
    226 
    227 	sep = "";
    228 	serr = NULL;
    229 	srsrc = NULL;
    230 	error = NULL;
    231 
    232 	/*
    233 	 * Get the proper arguments for the error.
    234 	 */
    235 	switch (err) {
    236 	case ERR_CMD_ABORT:
    237 	case ERR_CMD_FAIL:
    238 	case ERR_CMD_NACK:
    239 		get_cmd(cmd, ap, v);
    240 		check_tgt(a->target, target);
    241 		len += strlen(cmd) + strlen(target);
    242 		DBG("<%s><%s>", cmd, target);
    243 		break;
    244 	case ERR_CMD_NOTSUPP:
    245 		get_cmd(cmd, ap, v);
    246 		if (a->tgt == AP_BOARD)
    247 			target = STR_BD;
    248 		else
    249 			check_tgt(a->cname, target);
    250 		len += strlen(cmd) + strlen(target);
    251 		DBG("<%s><%s>", cmd, target);
    252 		break;
    253 	case ERR_AP_INVAL:
    254 		check_tgt((char *)a->apid, target);
    255 		len += strlen(target);
    256 		DBG("<%s>", target);
    257 		break;
    258 	case ERR_CMD_INVAL:
    259 	case ERR_CM_INVAL:
    260 	case ERR_OPT_INVAL:
    261 	case ERR_OPT_NOVAL:
    262 	case ERR_OPT_VAL:
    263 	case ERR_OPT_BADVAL:
    264 		get_str(option, ap, STR_NULL);
    265 		len += strlen(option);
    266 		DBG("<%s>", option);
    267 		if (err != ERR_OPT_BADVAL)
    268 			break;
    269 		get_str(value, ap, STR_NULL);
    270 		len += strlen(value);
    271 		DBG("<%s>", value);
    272 		break;
    273 	case ERR_TRANS_INVAL: {
    274 		cfga_stat_t rs, os;
    275 
    276 		get_cmd(cmd, ap, v);
    277 		check_tgt(a->target, target);
    278 		len += strlen(cmd) + strlen(target);
    279 		ap_state(a, &rs, &os);
    280 		rstate = ap_stnames[rs];
    281 		ostate = ap_stnames[os];
    282 		len += strlen(rstate) + strlen(ostate);
    283 		DBG("<%s><%s><%s><%s>", cmd, target, rstate, ostate);
    284 		break;
    285 	}
    286 	case ERR_RCM_CMD: {
    287 
    288 		get_cmd(cmd, ap, v);
    289 		check_tgt(a->target, target);
    290 		len += strlen(cmd) + strlen(target);
    291 		DBG("<%s><%s>", cmd, target);
    292 
    293 		if ((ap_rcm_info(a, &rinfostr) == 0) && (rinfostr != NULL)) {
    294 			len += strlen(rinfostr);
    295 		}
    296 
    297 		break;
    298 	}
    299 	case ERR_LIB_OPEN:
    300 		get_str(path, ap, STR_NULL);
    301 		get_str(error, ap, "");
    302 		if (str_valid(error))
    303 			sep = STR_SEP;
    304 		DBG("<%s><%s>", path, error);
    305 		break;
    306 	case ERR_LIB_SYM:
    307 		get_str(path, ap, STR_NULL);
    308 		get_str(sym, ap, STR_NULL);
    309 		DBG("<%s><%s>", path, sym);
    310 		break;
    311 	case ERR_STAT:
    312 		get_str(path, ap, STR_NULL);
    313 		break;
    314 	case ERR_PLUGIN:
    315 		get_str(msg, ap, STR_NULL);
    316 		break;
    317 	default:
    318 		DBG("<NOARGS>");
    319 		break;
    320 	}
    321 
    322 	va_end(ap);
    323 
    324 	/*
    325 	 * In case of a system error, get the reason for
    326 	 * the failure as well as the resource if availbale.
    327 	 * If we already got some error info (e.g. from RCM)
    328 	 * don't bother looking.
    329 	 */
    330 	if (!str_valid(error) && errno) {
    331 		sep = STR_SEP;
    332 		sysrsrc = NULL;
    333 		if ((syserr = ap_sys_err(a, &sysrsrc)) == NULL)
    334 			syserr = STR_ERR_UNKNOWN;
    335 		else
    336 			serr = syserr;
    337 
    338 		syserr = dgettext(TEXT_DOMAIN, syserr);
    339 
    340 		if (sysrsrc == NULL)
    341 			sysrsrc = "";
    342 		else
    343 			srsrc = sysrsrc;
    344 
    345 		len += strlen(syserr) + strlen(sysrsrc);
    346 
    347 		if (str_valid(sysrsrc)) {
    348 			rsep = STR_SEP;
    349 			len += strlen(rsep);
    350 		} else
    351 			rsep = "";
    352 
    353 		DBG("<%s><%s><%s>", syserr, rsep, sysrsrc);
    354 
    355 	} else
    356 		syserr = rsep = sysrsrc = "";
    357 
    358 	DBG("\n");
    359 
    360 	if ((p = (char *)calloc(len, 1)) != NULL)
    361 		*errstring = p;
    362 
    363 	/*
    364 	 * Print the string with appropriate arguments.
    365 	 */
    366 	switch (err) {
    367 	case ERR_CMD_FAIL:
    368 		(void) snprintf(p, len, fmt, cmd, target,
    369 			syserr, rsep, sysrsrc);
    370 		break;
    371 	case ERR_CMD_ABORT:
    372 	case ERR_CMD_NACK:
    373 	case ERR_CMD_NOTSUPP:
    374 		(void) snprintf(p, len, fmt, cmd, target);
    375 		break;
    376 	case ERR_AP_INVAL:
    377 		(void) snprintf(p, len, fmt, target);
    378 		break;
    379 	case ERR_CMD_INVAL:
    380 	case ERR_CM_INVAL:
    381 	case ERR_OPT_INVAL:
    382 	case ERR_OPT_NOVAL:
    383 	case ERR_OPT_VAL:
    384 		(void) snprintf(p, len, fmt, option);
    385 		break;
    386 	case ERR_OPT_BADVAL:
    387 		(void) snprintf(p, len, fmt, option, value);
    388 		break;
    389 	case ERR_TRANS_INVAL:
    390 		(void) snprintf(p, len, fmt, cmd, rstate, ostate, target);
    391 		break;
    392 	case ERR_SIG_CHANGE:
    393 	case ERR_RCM_HANDLE:
    394 		(void) snprintf(p, len, fmt);
    395 		break;
    396 	case ERR_RCM_CMD:
    397 		/*
    398 		 * If the rinfostr has a string, then the librcm has returned
    399 		 * us a text field of its reasons why the command failed.
    400 		 *
    401 		 * If the rinfostr is not returning data, we will use
    402 		 * the standard ap_err_fmts[] for the rcm error.
    403 		 */
    404 		if (rinfostr != NULL)
    405 			(void) snprintf(p, len, "%s", rinfostr);
    406 		else
    407 			(void) snprintf(p, len, fmt, cmd, target);
    408 		break;
    409 	case ERR_LIB_OPEN:
    410 		(void) snprintf(p, len, fmt, path, sep, error);
    411 		break;
    412 	case ERR_LIB_SYM:
    413 		(void) snprintf(p, len, fmt, sym, path);
    414 		break;
    415 	case ERR_STAT:
    416 		(void) snprintf(p, len, fmt, path, syserr);
    417 		break;
    418 	case ERR_NOMEM:
    419 		(void) snprintf(p, len, fmt);
    420 		break;
    421 	case ERR_PLUGIN:
    422 		(void) snprintf(p, len, fmt, a->class, msg);
    423 		break;
    424 	default:
    425 		break;
    426 	}
    427 
    428 	if (serr)
    429 		free(serr);
    430 	if (srsrc)
    431 		free(srsrc);
    432 }
    433 
    434 /*
    435  * ap_msg() accepts a variable number of message IDs and constructs
    436  * a corresponding message string which is printed via the message print
    437  * routine argument.  ap_msg() internationalizes the appropriate portion
    438  * of the message.
    439  */
    440 void
    441 ap_msg(apd_t *a, ...)
    442 {
    443 	int v;
    444 	int len;
    445 	char *p;
    446 	const char *fmt;
    447 	char *cmd;
    448 	char *target;
    449 	struct cfga_msg *msgp;
    450 	va_list ap;
    451 
    452 	DBG("ap_msg(%p)\n", (void *)a);
    453 
    454 	if (a == NULL || ap_getopt(a, OPT_VERBOSE) == 0)
    455 		return;
    456 
    457 	msgp = a->msgp;
    458 
    459 	if (msgp == NULL || msgp->message_routine == NULL)
    460 		return;
    461 
    462 	va_start(ap, a);
    463 
    464 	v = va_arg(ap, int);
    465 
    466 	if ((fmt = ap_msg_fmt(v)) == NULL)
    467 		fmt = STR_MSG_UNKNOWN;
    468 	fmt = dgettext(TEXT_DOMAIN, fmt);
    469 	len = strlen(fmt) + 128;	/* slop */
    470 
    471 	DBG("<%d>", v);
    472 
    473 	switch (v) {
    474 	case MSG_ISSUE:
    475 	case MSG_SKIP:
    476 	case MSG_ABORT:
    477 	case MSG_FAIL:
    478 	case MSG_DONE:
    479 		get_cmd(cmd, ap, v);
    480 		get_tgt(target, ap);
    481 		DBG("<%s><%s>\n", cmd, target);
    482 		len += strlen(cmd) + strlen(target);
    483 		break;
    484 	default:
    485 		break;
    486 	}
    487 
    488 	va_end(ap);
    489 
    490 	if ((p = (char *)calloc(len, 1)) == NULL)
    491 		return;
    492 
    493 	(void) snprintf(p, len, fmt, cmd, target);
    494 
    495 	(*msgp->message_routine)(msgp->appdata_ptr, p);
    496 	free(p);
    497 }
    498 
    499 int
    500 ap_confirm(apd_t *a)
    501 {
    502 	int rc;
    503 	char *msg;
    504 	struct cfga_confirm *confp;
    505 
    506 	if (a == NULL)
    507 		return (0);
    508 
    509 	confp = a->confp;
    510 
    511 	if (confp == NULL || confp->confirm == NULL)
    512 		return (0);
    513 
    514 	msg = dgettext(TEXT_DOMAIN, ap_msg_fmt(MSG_SUSPEND));
    515 
    516 	rc = (*confp->confirm)(confp->appdata_ptr, msg);
    517 
    518 	return (rc);
    519 }
    520