OpenSolaris_b135/lib/libunistat/common/spcs_s_u.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/*
 *	The SPCS status support user utilities
 *	See spcs_s_u.h and the docs subdirectory for functional spec
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <locale.h>
#include <libintl.h>
#include <sys/unistat/spcs_s.h>
#include <sys/unistat/spcs_s_u.h>
#include <sys/unistat/spcs_s_impl.h>
#include <sys/unistat/spcs_errors.h>
#include <sys/unistat/spcs_etext.h>
#include <sys/unistat/spcs_etrinkets.h>
#include <sys/unistat/spcs_dtrinkets.h>

/*
 *	Initialize ioctl status storage to "remove" any old status present
 */

void
spcs_s_uinit(spcs_s_info_t ustatus)
{
	spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
	p->major = SPCS_S_MAJOR_REV;
	p->minor = SPCS_S_MINOR_REV;
	p->icount = 0;
	p->scount = 0;
	p->tcount = 0;
}

/*
 *	Create and initialize local status. Call this prior to invoking
 * 	an ioctl.
 */

spcs_s_info_t
spcs_s_ucreate()
{
	static int need_to_bind = 1;
	spcs_s_pinfo_t *ustatus;

	if (need_to_bind) {
	    (void) setlocale(LC_ALL, "");
	    (void) bindtextdomain("unistat", LIBUNISTAT_LOCALE);
	    need_to_bind = 0;
	};

	ustatus = (spcs_s_pinfo_t *)malloc(sizeof (spcs_s_pinfo_t));
	spcs_s_uinit((spcs_s_info_t)ustatus);

	return ((spcs_s_info_t)ustatus);
}

/*
 *	Return the idata index of the last status code in the array (i.e.
 *	the "youngest" code present). The assumption is that the caller has
 *	checked to see that pcount is nonzero.
 */

ISSTATIC int
last_code_idx(spcs_s_pinfo_t *p)
{
	int last = 0;
	int idx = 0;

	while (idx < p->icount) {
		last = idx;
		idx += p->idata[idx].f.sup_count + 1;
	}
	return (last);
}

/*
 *	Return a string with the module label and error message text or NULL
 *      if none left
 */

char *
spcs_s_string(spcs_s_info_t ustatus, char *msg)
{
	spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
	int idx;
	int sup;
	int s;
	char *format;
	char *sp[SPCS_S_MAXSUPP];
	char mtemp[SPCS_S_MAXLINE];

	if (p->icount > 0) {
		idx = last_code_idx(p);
		strcpy(msg, module_names[p->idata[idx].f.module]);
		strcat(msg, ": ");
		sup = p->idata[idx].f.sup_count;

		if (p->idata[idx].f.module)
			/*
			 * The gettext formal parameter is a const char*
			 * I guess the gettext creator couldn't imagine
			 * needing a variable string. If there is an underlying
			 * routine that can be called it should be used.
			 * otherwise there will be a compiler warning about this
			 * line FOREVER (TS).
			 */
			format = (char *)dgettext("unistat",
				SPCS_S_MSG[p->idata[idx].f.module]
				[p->idata[idx].f.code]);

		else
			format = strerror(p->idata[idx].f.code);

		/*
		 * step across the status code to the first supplemental data
		 * descriptor.
		 */

		idx += 1;

		/*
		 * Initialize the array with empty string pointers so we don't
		 * seg fault if there are actually fewer values than "%s"
		 * format descriptors.
		 */
		for (s = 0; s < SPCS_S_MAXSUPP; s++)
			sp[s] = "";

		/*
		 * Walk through the supplemental value descriptors and build
		 * an array of string pointers.
		 */

		for (s = 0; s < sup; s++) {
			sp[s] = (char *)(p->sdata + p->idata[idx+s].su.offset);
		}

		/*
		 * Now format the message. The unused string pointers will be
		 * ignored.
		 * NOTE: Any change to SPCS_S_MAXSUPP requires a change to
		 * this sprintf.
		 */

		sprintf(mtemp, format, sp[0], sp[1], sp[2], sp[3], sp[4], sp[5],
				    sp[6], sp[7]);

		/* remove the code and its supplemental info */

		p->icount -= (sup + 1);

		return (strcat(msg, mtemp));
	} else
		return (NULL);
}

/*
 *	Write status info
 */

void
spcs_s_report(spcs_s_info_t ustatus, FILE *fd)
{
	spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
	short saved_count = p->icount;
	char msg[SPCS_S_MAXTEXT];
	char *sp;
	char *se;
	int first_time = 1;

	do {
		if (sp = spcs_s_string(ustatus, msg))
			fprintf(fd, "%s\n", sp);
		else if (first_time && (errno > 0)) {
			/*
			 * This covers the case where Solaris aborted the
			 * operation or the ioctl service code got an EFAULT
			 * or something from copyin or couldn't allocate the
			 * kernel status structure. If errno > 0 but not a
			 * valid Solaris error code the extended error is
			 * decoded and printed.
			 */
			se = strerror(errno);
			if (se)
				fprintf(fd, "%s\n", se);
			else {
				spcs_s_udata_t spcs_errno;

				spcs_errno.i = errno;
				fprintf(fd, "%s: %s\n",
					module_names[spcs_errno.f.module],
					dgettext("unistat",
						SPCS_S_MSG[spcs_errno.f.module]
						[spcs_errno.f.code]));

			}
		}
		first_time = 0;
	} while (sp);

	p->icount = saved_count;
}

/*ARGSUSED*/
void
spcs_s_exception(spcs_s_info_t ustatus, void *env)
{
}

/*
 *	Release (free) ioctl status storage.
 */

void
spcs_s_ufree(spcs_s_info_t *ustatus_a)
{
	free((void *)*ustatus_a);
	*ustatus_a = NULL;
}