xref: /onnv-gate/usr/src/lib/libcpc/common/obsoleted.c (revision 398:84b7b4438647)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*398Srab  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/stat.h>
310Sstevel@tonic-gate #include <sys/syscall.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <strings.h>
380Sstevel@tonic-gate #include <stdarg.h>
390Sstevel@tonic-gate #include <signal.h>
400Sstevel@tonic-gate #include <libintl.h>
410Sstevel@tonic-gate #include <dirent.h>
420Sstevel@tonic-gate #include <sys/cpc_impl.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include "libcpc.h"
450Sstevel@tonic-gate #include "libcpc_impl.h"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * CPC library handle for use by CPCv1 implementation.
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate cpc_t *__cpc = NULL;
510Sstevel@tonic-gate mutex_t __cpc_lock;		/* protects __cpc handle */
520Sstevel@tonic-gate int __cpc_v1_cpuver;		/* CPU version in use by CPCv1 client */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #ifdef __sparc
550Sstevel@tonic-gate uint64_t __cpc_v1_pcr;		/* last bound %pcr value */
560Sstevel@tonic-gate #else
570Sstevel@tonic-gate uint32_t __cpc_v1_pes[2];	/* last bound %pes values */
580Sstevel@tonic-gate #endif /* __sparc */
590Sstevel@tonic-gate 
600Sstevel@tonic-gate int
__cpc_init(void)610Sstevel@tonic-gate __cpc_init(void)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	const char *fn = "__cpc_init";
640Sstevel@tonic-gate 	extern cpc_t *__cpc;	/* CPC handle for obsolete clients to share */
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	(void) mutex_lock(&__cpc_lock);
670Sstevel@tonic-gate 	if (__cpc == NULL && (__cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
680Sstevel@tonic-gate 		__cpc_error(fn, dgettext(TEXT_DOMAIN,
690Sstevel@tonic-gate 		    "Couldn't open CPC library handle\n"));
700Sstevel@tonic-gate 		(void) mutex_unlock(&__cpc_lock);
710Sstevel@tonic-gate 		return (-1);
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate 	(void) mutex_unlock(&__cpc_lock);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	return (0);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate int
cpc_bind_event(cpc_event_t * this,int flags)790Sstevel@tonic-gate cpc_bind_event(cpc_event_t *this, int flags)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	cpc_set_t		*set;
820Sstevel@tonic-gate 	cpc_request_t		*rp;
830Sstevel@tonic-gate 	int			ret;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (this == NULL) {
860Sstevel@tonic-gate 		(void) cpc_rele();
870Sstevel@tonic-gate 		return (0);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if (__cpc_init() != 0) {
910Sstevel@tonic-gate 		errno = ENXIO;
920Sstevel@tonic-gate 		return (-1);
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * The cpuver and control fields of the cpc_event_t must be saved off
970Sstevel@tonic-gate 	 * for later. The user may call cpc_take_sample(), expecting these to
980Sstevel@tonic-gate 	 * be copied into a different cpc_event_t struct by the kernel. We have
990Sstevel@tonic-gate 	 * to fake that behavior for CPCv1 clients.
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	__cpc_v1_cpuver = this->ce_cpuver;
1020Sstevel@tonic-gate #ifdef __sparc
1030Sstevel@tonic-gate 	__cpc_v1_pcr = this->ce_pcr;
1040Sstevel@tonic-gate #else
1050Sstevel@tonic-gate 	__cpc_v1_pes[0] = this->ce_pes[0];
1060Sstevel@tonic-gate 	__cpc_v1_pes[1] = this->ce_pes[1];
1070Sstevel@tonic-gate #endif /* __sparc */
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) {
1100Sstevel@tonic-gate 		errno = EINVAL;
1110Sstevel@tonic-gate 		return (-1);
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	/*
1150Sstevel@tonic-gate 	 * Convert flags to CPC2.
1160Sstevel@tonic-gate 	 */
1170Sstevel@tonic-gate 	if (flags & CPC_BIND_EMT_OVF) {
1180Sstevel@tonic-gate 		for (rp = set->cs_request; rp != NULL; rp = rp->cr_next)
1190Sstevel@tonic-gate 			rp->cr_flags |= CPC_OVF_NOTIFY_EMT;
1200Sstevel@tonic-gate 		flags &= ~CPC_BIND_EMT_OVF;
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	ret = cpc_bind_curlwp(__cpc, set, flags);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	(void) cpc_set_destroy(__cpc, set);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	return (ret);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate int
cpc_take_sample(cpc_event_t * this)1310Sstevel@tonic-gate cpc_take_sample(cpc_event_t *this)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	this->ce_cpuver = __cpc_v1_cpuver;
1340Sstevel@tonic-gate #ifdef __sparc
1350Sstevel@tonic-gate 	this->ce_pcr = __cpc_v1_pcr;
1360Sstevel@tonic-gate #else
1370Sstevel@tonic-gate 	this->ce_pes[0] = __cpc_v1_pes[0];
1380Sstevel@tonic-gate 	this->ce_pes[1] = __cpc_v1_pes[1];
1390Sstevel@tonic-gate #endif /* __sparc */
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	return (syscall(SYS_cpc, CPC_SAMPLE, -1, this->ce_pic, &this->ce_hrt,
1420Sstevel@tonic-gate 	    &CPC_TICKREG(this), 0));
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate int
cpc_count_usr_events(int enable)1460Sstevel@tonic-gate cpc_count_usr_events(int enable)
1470Sstevel@tonic-gate {
148*398Srab 	return (syscall(SYS_cpc, CPC_USR_EVENTS, -1, enable, 0));
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate int
cpc_count_sys_events(int enable)1520Sstevel@tonic-gate cpc_count_sys_events(int enable)
1530Sstevel@tonic-gate {
154*398Srab 	return (syscall(SYS_cpc, CPC_SYS_EVENTS, -1, enable, 0));
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate int
cpc_rele(void)1580Sstevel@tonic-gate cpc_rele(void)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	return (syscall(SYS_cpc, CPC_RELE, -1, NULL, 0));
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate  * See if the system call is working and installed.
1650Sstevel@tonic-gate  *
1660Sstevel@tonic-gate  * We invoke the system call with nonsense arguments - if it's
1670Sstevel@tonic-gate  * there and working correctly, it will return EINVAL.
1680Sstevel@tonic-gate  *
1690Sstevel@tonic-gate  * (This avoids the user getting a SIGSYS core dump when they attempt
1700Sstevel@tonic-gate  * to bind on older hardware)
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate int
cpc_access(void)1730Sstevel@tonic-gate cpc_access(void)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	void (*handler)(int);
1760Sstevel@tonic-gate 	int error = 0;
1770Sstevel@tonic-gate 	const char fn[] = "access";
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	handler = signal(SIGSYS, SIG_IGN);
1800Sstevel@tonic-gate 	if (syscall(SYS_cpc, -1, -1, NULL, 0) == -1 &&
1810Sstevel@tonic-gate 	    errno != EINVAL)
1820Sstevel@tonic-gate 		error = errno;
1830Sstevel@tonic-gate 	(void) signal(SIGSYS, handler);
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	switch (error) {
1860Sstevel@tonic-gate 	case EAGAIN:
1870Sstevel@tonic-gate 		__cpc_error(fn, dgettext(TEXT_DOMAIN, "Another process may be "
1880Sstevel@tonic-gate 		    "sampling system-wide CPU statistics\n"));
1890Sstevel@tonic-gate 		break;
1900Sstevel@tonic-gate 	case ENOSYS:
1910Sstevel@tonic-gate 		__cpc_error(fn,
1920Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "CPU performance counters "
1930Sstevel@tonic-gate 		    "are inaccessible on this machine\n"));
1940Sstevel@tonic-gate 		break;
1950Sstevel@tonic-gate 	default:
1960Sstevel@tonic-gate 		__cpc_error(fn, "%s\n", strerror(errno));
1970Sstevel@tonic-gate 		break;
1980Sstevel@tonic-gate 	case 0:
1990Sstevel@tonic-gate 		return (0);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	errno = error;
2030Sstevel@tonic-gate 	return (-1);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate /*
2070Sstevel@tonic-gate  * To look at the system-wide counters, we have to open the
2080Sstevel@tonic-gate  * 'shared' device.  Once that device is open, no further contexts
2090Sstevel@tonic-gate  * can be installed (though one open is needed per CPU)
2100Sstevel@tonic-gate  */
2110Sstevel@tonic-gate int
cpc_shared_open(void)2120Sstevel@tonic-gate cpc_shared_open(void)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	const char driver[] = CPUDRV_SHARED;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	return (open(driver, O_RDWR));
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate void
cpc_shared_close(int fd)2200Sstevel@tonic-gate cpc_shared_close(int fd)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	(void) cpc_shared_rele(fd);
2230Sstevel@tonic-gate 	(void) close(fd);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate int
cpc_shared_bind_event(int fd,cpc_event_t * this,int flags)2270Sstevel@tonic-gate cpc_shared_bind_event(int fd, cpc_event_t *this, int flags)
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	extern cpc_t		*__cpc;
2300Sstevel@tonic-gate 	cpc_set_t		*set;
2310Sstevel@tonic-gate 	int			ret;
2320Sstevel@tonic-gate 	char			*packed_set;
2330Sstevel@tonic-gate 	size_t			packsize;
2340Sstevel@tonic-gate 	int			subcode;
2350Sstevel@tonic-gate 	__cpc_args_t		cpc_args;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (this == NULL) {
2380Sstevel@tonic-gate 		(void) cpc_shared_rele(fd);
2390Sstevel@tonic-gate 		return (0);
2400Sstevel@tonic-gate 	} else if (flags != 0) {
2410Sstevel@tonic-gate 		errno = EINVAL;
2420Sstevel@tonic-gate 		return (-1);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (__cpc_init() != 0) {
2460Sstevel@tonic-gate 		errno = ENXIO;
2470Sstevel@tonic-gate 		return (-1);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) {
2510Sstevel@tonic-gate 		errno = EINVAL;
2520Sstevel@tonic-gate 		return (-1);
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	__cpc_v1_cpuver = this->ce_cpuver;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) {
2580Sstevel@tonic-gate 		errno = ENOMEM;
2590Sstevel@tonic-gate 		return (-1);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	cpc_args.udata1 = packed_set;
2630Sstevel@tonic-gate 	cpc_args.udata2 = (void *)packsize;
2640Sstevel@tonic-gate 	cpc_args.udata3 = (void *)&subcode;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	ret = ioctl(fd, CPCIO_BIND, &cpc_args);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	free(packed_set);
2690Sstevel@tonic-gate 	(void) cpc_set_destroy(__cpc, set);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	return (ret);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate int
cpc_shared_take_sample(int fd,cpc_event_t * this)2750Sstevel@tonic-gate cpc_shared_take_sample(int fd, cpc_event_t *this)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	__cpc_args_t args;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	args.udata1 = this->ce_pic;
2800Sstevel@tonic-gate 	args.udata2 = &this->ce_hrt;
2810Sstevel@tonic-gate 	args.udata3 = &CPC_TICKREG(this);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	this->ce_cpuver = __cpc_v1_cpuver;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	return (ioctl(fd, CPCIO_SAMPLE, &args));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate int
cpc_shared_rele(int fd)2890Sstevel@tonic-gate cpc_shared_rele(int fd)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	return (ioctl(fd, CPCIO_RELE, 0));
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate int
cpc_pctx_bind_event(pctx_t * pctx,id_t lwpid,cpc_event_t * event,int flags)2950Sstevel@tonic-gate cpc_pctx_bind_event(pctx_t *pctx, id_t lwpid, cpc_event_t *event, int flags)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	cpc_set_t		*set;
2980Sstevel@tonic-gate 	int			ret;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (event == NULL)
3010Sstevel@tonic-gate 		return (cpc_pctx_rele(pctx, lwpid));
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (__cpc_init() != 0) {
3040Sstevel@tonic-gate 		errno = ENXIO;
3050Sstevel@tonic-gate 		return (-1);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	else if (flags != 0) {
3090Sstevel@tonic-gate 		errno = EINVAL;
3100Sstevel@tonic-gate 		return (-1);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	if ((set = __cpc_eventtoset(__cpc, event, flags)) == NULL) {
3140Sstevel@tonic-gate 		errno = EINVAL;
3150Sstevel@tonic-gate 		return (-1);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/*
3190Sstevel@tonic-gate 	 * The cpuver and control fields of the cpc_event_t must be saved off
3200Sstevel@tonic-gate 	 * for later. The user may call cpc_take_sample(), expecting these to
3210Sstevel@tonic-gate 	 * be copied into a different cpc_event_t struct by the kernel. We have
3220Sstevel@tonic-gate 	 * to fake that behavior for CPCv1 clients.
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	__cpc_v1_cpuver = event->ce_cpuver;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	ret = cpc_bind_pctx(__cpc, pctx, lwpid, set, 0);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	(void) cpc_set_destroy(__cpc, set);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	return (ret);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate int
cpc_pctx_take_sample(pctx_t * pctx,id_t lwpid,cpc_event_t * event)3340Sstevel@tonic-gate cpc_pctx_take_sample(pctx_t *pctx, id_t lwpid, cpc_event_t *event)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	event->ce_cpuver = __cpc_v1_cpuver;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	return (__pctx_cpc(pctx, __cpc, CPC_SAMPLE, lwpid, event->ce_pic,
3390Sstevel@tonic-gate 	    &event->ce_hrt, &CPC_TICKREG(event), CPC1_BUFSIZE));
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate /*
3430Sstevel@tonic-gate  * Given a process context and an lwpid, mark the CPU performance
3440Sstevel@tonic-gate  * counter context as invalid.
3450Sstevel@tonic-gate  */
3460Sstevel@tonic-gate int
cpc_pctx_invalidate(pctx_t * pctx,id_t lwpid)3470Sstevel@tonic-gate cpc_pctx_invalidate(pctx_t *pctx, id_t lwpid)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 	return (__pctx_cpc(pctx, __cpc, CPC_INVALIDATE, lwpid, 0, 0, 0, 0));
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate /*
3530Sstevel@tonic-gate  * Given a process context and an lwpid, remove all our
3540Sstevel@tonic-gate  * hardware context from it.
3550Sstevel@tonic-gate  */
3560Sstevel@tonic-gate int
cpc_pctx_rele(pctx_t * pctx,id_t lwpid)3570Sstevel@tonic-gate cpc_pctx_rele(pctx_t *pctx, id_t lwpid)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	return (__pctx_cpc(pctx, __cpc, CPC_RELE, lwpid, 0, 0, 0, 0));
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate static cpc_errfn_t *__cpc_uerrfn;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate /*PRINTFLIKE2*/
3650Sstevel@tonic-gate void
__cpc_error(const char * fn,const char * fmt,...)3660Sstevel@tonic-gate __cpc_error(const char *fn, const char *fmt, ...)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	va_list ap;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	va_start(ap, fmt);
3710Sstevel@tonic-gate 	if (__cpc_uerrfn)
3720Sstevel@tonic-gate 		__cpc_uerrfn(fn, fmt, ap);
3730Sstevel@tonic-gate 	else {
3740Sstevel@tonic-gate 		(void) fprintf(stderr, "libcpc: %s: ", fn);
3750Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 	va_end(ap);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate void
cpc_seterrfn(cpc_errfn_t * errfn)3810Sstevel@tonic-gate cpc_seterrfn(cpc_errfn_t *errfn)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	__cpc_uerrfn = errfn;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate /*
3870Sstevel@tonic-gate  * cpc_version() is only for CPC1 clients.
3880Sstevel@tonic-gate  */
3890Sstevel@tonic-gate uint_t __cpc_workver = CPC_VER_1;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate uint_t
cpc_version(uint_t ver)3920Sstevel@tonic-gate cpc_version(uint_t ver)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	__cpc_workver = CPC_VER_1;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	switch (ver) {
3970Sstevel@tonic-gate 	case CPC_VER_NONE:
3980Sstevel@tonic-gate 	case CPC_VER_CURRENT:
3990Sstevel@tonic-gate 		return (CPC_VER_CURRENT);
4000Sstevel@tonic-gate 	case CPC_VER_1:
4010Sstevel@tonic-gate 		/*
4020Sstevel@tonic-gate 		 * As long as the client is using cpc_version() at all, it is
4030Sstevel@tonic-gate 		 * a CPCv1 client.  We still allow CPCv1 clients to compile on
4040Sstevel@tonic-gate 		 * CPCv2 systems.
4050Sstevel@tonic-gate 		 */
4060Sstevel@tonic-gate 		return (CPC_VER_1);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	return (CPC_VER_NONE);
4100Sstevel@tonic-gate }
411