12264Sjacobs /*
22264Sjacobs  * CDDL HEADER START
32264Sjacobs  *
42264Sjacobs  * The contents of this file are subject to the terms of the
52264Sjacobs  * Common Development and Distribution License (the "License").
62264Sjacobs  * You may not use this file except in compliance with the License.
72264Sjacobs  *
82264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92264Sjacobs  * or http://www.opensolaris.org/os/licensing.
102264Sjacobs  * See the License for the specific language governing permissions
112264Sjacobs  * and limitations under the License.
122264Sjacobs  *
132264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
142264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
162264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
172264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
182264Sjacobs  *
192264Sjacobs  * CDDL HEADER END
202264Sjacobs  */
212264Sjacobs 
222264Sjacobs /*
232264Sjacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
242264Sjacobs  * Use is subject to license terms.
252264Sjacobs  *
262264Sjacobs  */
272264Sjacobs 
282264Sjacobs /* $Id: service.c 172 2006-05-24 20:54:00Z njacobs $ */
292264Sjacobs 
302264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
312264Sjacobs 
322264Sjacobs /*LINTLIBRARY*/
332264Sjacobs 
342264Sjacobs #include <stdlib.h>
352264Sjacobs #include <stdio.h>
362264Sjacobs #include <stdarg.h>
372264Sjacobs #include <string.h>
382264Sjacobs #include <alloca.h>
392264Sjacobs #include <libintl.h>
402264Sjacobs #include <papi_impl.h>
412264Sjacobs #include <config-site.h>
422264Sjacobs 
432264Sjacobs static int
442264Sjacobs interposed_auth_callback(papi_service_t handle, void *app_data)
452264Sjacobs {
462264Sjacobs 	int result = -1;
472264Sjacobs 	service_t *svc = app_data;
482264Sjacobs 
492264Sjacobs 	if (svc != NULL)
502264Sjacobs 		result = svc->authCB(svc, svc->app_data);
512264Sjacobs 
522264Sjacobs 	return (result);
532264Sjacobs }
542264Sjacobs 
552264Sjacobs static char *
562264Sjacobs default_service_uri(char *fallback)
572264Sjacobs {
582264Sjacobs 	char *result = NULL;
592264Sjacobs 
602264Sjacobs 	if ((result = getenv("PAPI_SERVICE_URI")) == NULL) {
612264Sjacobs 		char *cups;
622264Sjacobs 
632264Sjacobs 		if ((cups = getenv("CUPS_SERVER")) != NULL) {
642264Sjacobs 			char buf[BUFSIZ];
652264Sjacobs 
662264Sjacobs 			snprintf(buf, sizeof (buf), "ipp://%s/printers/", cups);
672264Sjacobs 			result = strdup(buf);
682264Sjacobs 		}
692264Sjacobs 	}
702264Sjacobs 
712264Sjacobs 	if (result == NULL)
722264Sjacobs 		result = fallback;
732264Sjacobs 
742264Sjacobs 	return (result);
752264Sjacobs }
762264Sjacobs 
772264Sjacobs static char *
782264Sjacobs default_print_service()
792264Sjacobs {
802264Sjacobs 	static char *result = NULL;
812264Sjacobs 
822264Sjacobs 	if (result == NULL) {
832264Sjacobs 		char *service_uri = default_service_uri(DEFAULT_SERVICE_URI);
842264Sjacobs 		uri_t *uri = NULL;
852264Sjacobs 
862264Sjacobs 		if (uri_from_string(service_uri, &uri) != -1)
872264Sjacobs 			result = strdup(uri->scheme);
882264Sjacobs 
892264Sjacobs 		if (uri != NULL)
902264Sjacobs 			uri_free(uri);
912264Sjacobs 	}
922264Sjacobs 
932264Sjacobs 	return (result);
942264Sjacobs }
952264Sjacobs 
962264Sjacobs static papi_status_t
972264Sjacobs service_load(service_t *svc, char *name)
982264Sjacobs {
992264Sjacobs 	papi_status_t result;
1002264Sjacobs 	char *scheme = default_print_service();
1012264Sjacobs 
1022264Sjacobs 	if (svc->so_handle != NULL)	/* already loaded */
1032264Sjacobs 		return (PAPI_OK);
1042264Sjacobs 
1052264Sjacobs 	if (name == NULL)		/* no info, can't load yet */
1062264Sjacobs 		return (PAPI_OK);
1072264Sjacobs 
1082264Sjacobs 	/* Lookup the printer in the configuration DB */
1092264Sjacobs 	svc->attributes = getprinterbyname((char *)name, NULL);
1102264Sjacobs 
1112264Sjacobs 	if (svc->attributes != NULL) {
1122264Sjacobs 		char *tmp = NULL;
1132264Sjacobs 
1142264Sjacobs 		/* Printer found (or was a URI), use the attribute data */
1152264Sjacobs 		papiAttributeListGetString(svc->attributes, NULL,
1162264Sjacobs 					"printer-uri-supported", &tmp);
1172264Sjacobs 		if (tmp != NULL)
1182264Sjacobs 			svc->name = strdup(tmp);
1192264Sjacobs 
1202264Sjacobs 		/* parse the URI and set the scheme(print service) */
1212264Sjacobs 		if (uri_from_string(svc->name, &svc->uri) != -1)
1222264Sjacobs 			scheme = (svc->uri)->scheme;
1232264Sjacobs 
1242264Sjacobs 		/* override the scheme if it was in the attributes */
1252264Sjacobs 		papiAttributeListGetString(svc->attributes, NULL,
1262264Sjacobs 					"print-service-module", &scheme);
1272264Sjacobs 
1282264Sjacobs 	} else	/* not found, assume it is the actual print service name */
1292264Sjacobs 		scheme = name;
1302264Sjacobs 
1312264Sjacobs 	result = psm_open(svc, scheme);
1322264Sjacobs 	switch (result) {
1332264Sjacobs 	case PAPI_OK:
1342264Sjacobs 		break;	/* no error */
1352264Sjacobs 	case PAPI_URI_SCHEME:
1362264Sjacobs 		result = PAPI_NOT_FOUND;
1372264Sjacobs #ifdef DEBUG
1382264Sjacobs 		detailed_error(svc, "Unable to load service for: %s", name);
1392264Sjacobs #endif
1402264Sjacobs 		break;
1412264Sjacobs 	default:	/* set the detailed message */
1422264Sjacobs 		detailed_error(svc, "Unable to load service (%s) for: %s",
1432264Sjacobs 				scheme, name);
1442264Sjacobs 	}
1452264Sjacobs 
1462264Sjacobs 	return (result);
1472264Sjacobs }
1482264Sjacobs 
1492264Sjacobs static papi_status_t
1502264Sjacobs service_send_peer(service_t *svc)
1512264Sjacobs {
1522264Sjacobs 	papi_status_t result = PAPI_OK;
1532264Sjacobs 
1542264Sjacobs 	if ((svc->peer_fd != -1) && (svc->so_handle != NULL) &&
1552264Sjacobs 	    (svc->svc_handle != NULL)) {
1562264Sjacobs 		papi_status_t (*f)();
1572264Sjacobs 
1582264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPeer");
1592264Sjacobs 
1602264Sjacobs 		if (f != NULL)
1612264Sjacobs 			result = f(svc->svc_handle, svc->peer_fd);
1622264Sjacobs 	}
1632264Sjacobs 
1642264Sjacobs 	return (result);
1652264Sjacobs }
1662264Sjacobs 
1672264Sjacobs papi_status_t
1682264Sjacobs service_connect(service_t *svc, char *name)
1692264Sjacobs {
1702264Sjacobs 	papi_status_t result = PAPI_NOT_POSSIBLE;
1712264Sjacobs 
1722264Sjacobs 	/* if there is no print service module loaded, try and load one. */
1732264Sjacobs 	if (svc->so_handle == NULL)
1742264Sjacobs 		result = service_load(svc, name);
1752264Sjacobs 	else if ((svc->name == NULL) && (name != NULL))
1762264Sjacobs 		svc->name = strdup(name);
1772264Sjacobs 
1782264Sjacobs 	/*
1792264Sjacobs 	 * the print service module is loaded, but we don't have a service
1802264Sjacobs 	 * handle.
1812264Sjacobs 	 */
1822264Sjacobs 	if (svc->so_handle != NULL) {
1832264Sjacobs 		papi_status_t (*f)();
1842264Sjacobs 
185*2928Sjacobs 		if (svc->svc_handle != NULL)	/* already connected? */
186*2928Sjacobs 			return (PAPI_OK);
187*2928Sjacobs 
1882264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceCreate");
1892264Sjacobs 
1902264Sjacobs 		if (f != NULL) {
1912264Sjacobs 			char *user = svc->user;
1922264Sjacobs 			char *password = svc->password;
1932264Sjacobs 
1942264Sjacobs 			/* if no API user, try the URI user */
1952264Sjacobs 			if ((user == NULL) && (svc->uri != NULL))
1962264Sjacobs 				user = (svc->uri)->user;
1972264Sjacobs 			/* if no API password, try the URI password */
1982264Sjacobs 			if ((password == NULL) && (svc->uri != NULL))
1992264Sjacobs 				password = (svc->uri)->password;
2002264Sjacobs 
2012264Sjacobs 			result = f(&svc->svc_handle, svc->name, user, password,
2022264Sjacobs 					(svc->authCB ? interposed_auth_callback
2032264Sjacobs 						: NULL),
2042264Sjacobs 					svc->encryption, svc);
2052264Sjacobs 			(void) service_send_peer(svc);
2062264Sjacobs 		}
2072264Sjacobs 	}
2082264Sjacobs 
2092264Sjacobs 	return (result);
2102264Sjacobs }
2112264Sjacobs 
2122264Sjacobs papi_status_t
2132264Sjacobs papiServiceCreate(papi_service_t *handle, char *service_name, char *user_name,
2142264Sjacobs 		char *password,
2152264Sjacobs 		int (*authCB)(papi_service_t svc, void *app_data),
2162264Sjacobs 		papi_encryption_t encryption, void *app_data)
2172264Sjacobs {
2182264Sjacobs 	papi_status_t result = PAPI_NOT_POSSIBLE;
2192264Sjacobs 	service_t *svc = NULL;
2202264Sjacobs 	uri_t *u = NULL;
2212264Sjacobs 
2222264Sjacobs 	if (handle == NULL)
2232264Sjacobs 		return (PAPI_BAD_ARGUMENT);
2242264Sjacobs 
2252264Sjacobs 	if ((*handle = svc = calloc(1, sizeof (*svc))) == NULL)
2262264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
2272264Sjacobs 
2282264Sjacobs 	svc->peer_fd = -1;
2292264Sjacobs 
2302264Sjacobs 	if (user_name != NULL)
2312264Sjacobs 		svc->user = strdup(user_name);
2322264Sjacobs 
2332264Sjacobs 	if (password != NULL)
2342264Sjacobs 		svc->password = strdup(password);
2352264Sjacobs 
2362264Sjacobs 	svc->encryption = encryption;
2372264Sjacobs 
2382264Sjacobs 	if (authCB != NULL)
2392264Sjacobs 		svc->authCB = authCB;
2402264Sjacobs 
2412264Sjacobs 	if (app_data != NULL)
2422264Sjacobs 		svc->app_data = app_data;
2432264Sjacobs 
2442264Sjacobs 	/* If not specified, get a "default" service from the environment */
2452264Sjacobs 	if (service_name == NULL)
2462264Sjacobs 		service_name = default_service_uri(NULL);
2472264Sjacobs 
2482264Sjacobs 	if (service_name != NULL) {
2492264Sjacobs 		result = service_load(svc, service_name);
2502264Sjacobs 		/* if the psm loaded and the svc contains a URI, connect */
2512264Sjacobs 		if ((result == PAPI_OK) && (svc->uri != NULL))
2522264Sjacobs 			result = service_connect(svc, service_name);
2532264Sjacobs 	} else
2542264Sjacobs 		result = PAPI_OK;
2552264Sjacobs 
2562264Sjacobs 	return (result);
2572264Sjacobs }
2582264Sjacobs 
2592264Sjacobs void
2602264Sjacobs papiServiceDestroy(papi_service_t handle)
2612264Sjacobs {
2622264Sjacobs 	if (handle != NULL) {
2632264Sjacobs 		service_t *svc = handle;
2642264Sjacobs 
2652264Sjacobs 		if (svc->so_handle != NULL) {
2662264Sjacobs 			if (svc->svc_handle != NULL) {
2672264Sjacobs 				void (*f)();
2682264Sjacobs 
2692264Sjacobs 				f = (void (*)())psm_sym(svc,
2702264Sjacobs 							"papiServiceDestroy");
2712264Sjacobs 				f(svc->svc_handle);
2722264Sjacobs 			}
2732264Sjacobs 			psm_close(svc->so_handle);
2742264Sjacobs 		}
2752264Sjacobs 		if (svc->attributes != NULL)
2762264Sjacobs 			papiAttributeListFree(svc->attributes);
2772264Sjacobs 		if (svc->name != NULL)
2782264Sjacobs 			free(svc->name);
2792264Sjacobs 		if (svc->user != NULL)
2802264Sjacobs 			free(svc->user);
2812264Sjacobs 		if (svc->password != NULL)
2822264Sjacobs 			free(svc->password);
2832264Sjacobs 		if (svc->uri != NULL)
2842264Sjacobs 			uri_free(svc->uri);
2852264Sjacobs 
2862264Sjacobs 		free(handle);
2872264Sjacobs 	}
2882264Sjacobs }
2892264Sjacobs 
2902264Sjacobs papi_status_t
2912264Sjacobs papiServiceSetPeer(papi_service_t handle, int fd)
2922264Sjacobs {
2932264Sjacobs 	papi_status_t result = PAPI_OK;
2942264Sjacobs 
2952264Sjacobs 	if (handle != NULL) {
2962264Sjacobs 		service_t *svc = handle;
2972264Sjacobs 
2982264Sjacobs 		svc->peer_fd = fd;
2992264Sjacobs 		result = service_send_peer(svc);
3002264Sjacobs 	} else
3012264Sjacobs 		result = PAPI_BAD_ARGUMENT;
3022264Sjacobs 
3032264Sjacobs 	return (result);
3042264Sjacobs }
3052264Sjacobs 
3062264Sjacobs papi_status_t
3072264Sjacobs papiServiceSetUserName(papi_service_t handle, char *user_name)
3082264Sjacobs {
3092264Sjacobs 	papi_status_t result = PAPI_OK;
3102264Sjacobs 
3112264Sjacobs 	if (handle != NULL) {
3122264Sjacobs 		service_t *svc = handle;
3132264Sjacobs 		papi_status_t (*f)();
3142264Sjacobs 
3152264Sjacobs 		if (svc->user != NULL)
3162264Sjacobs 			free(svc->user);
3172264Sjacobs 		if (user_name != NULL)
3182264Sjacobs 			svc->user = strdup(user_name);
3192264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetUserName");
3202264Sjacobs 		if (f != NULL)
3212264Sjacobs 			result = f(svc->svc_handle, user_name);
3222264Sjacobs 	} else
3232264Sjacobs 		result = PAPI_BAD_ARGUMENT;
3242264Sjacobs 
3252264Sjacobs 	return (result);
3262264Sjacobs }
3272264Sjacobs 
3282264Sjacobs papi_status_t
3292264Sjacobs papiServiceSetPassword(papi_service_t handle, char *password)
3302264Sjacobs {
3312264Sjacobs 	papi_status_t result = PAPI_OK;
3322264Sjacobs 
3332264Sjacobs 	if (handle != NULL) {
3342264Sjacobs 		service_t *svc = handle;
3352264Sjacobs 		papi_status_t (*f)();
3362264Sjacobs 
3372264Sjacobs 		if (svc->password != NULL)
3382264Sjacobs 			free(svc->password);
3392264Sjacobs 		if (password != NULL)
3402264Sjacobs 			svc->password = strdup(password);
3412264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPassword");
3422264Sjacobs 		if (f != NULL)
3432264Sjacobs 			result = f(svc->svc_handle, password);
3442264Sjacobs 	} else
3452264Sjacobs 		result = PAPI_BAD_ARGUMENT;
3462264Sjacobs 
3472264Sjacobs 	return (result);
3482264Sjacobs }
3492264Sjacobs 
3502264Sjacobs papi_status_t
3512264Sjacobs papiServiceSetEncryption(papi_service_t handle, papi_encryption_t encryption)
3522264Sjacobs {
3532264Sjacobs 	papi_status_t result = PAPI_OK;
3542264Sjacobs 
3552264Sjacobs 	if (handle != NULL) {
3562264Sjacobs 		service_t *svc = handle;
3572264Sjacobs 		papi_status_t (*f)();
3582264Sjacobs 
3592264Sjacobs 		svc->encryption = encryption;
3602264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc,
3612264Sjacobs 						"papiServiceSetEncryption");
3622264Sjacobs 		if (f != NULL)
3632264Sjacobs 			result = f(svc->svc_handle, encryption);
3642264Sjacobs 	} else
3652264Sjacobs 		result = PAPI_BAD_ARGUMENT;
3662264Sjacobs 
3672264Sjacobs 	return (result);
3682264Sjacobs }
3692264Sjacobs 
3702264Sjacobs papi_status_t
3712264Sjacobs papiServiceSetAuthCB(papi_service_t handle,
3722264Sjacobs 		int (*authCB)(papi_service_t svc, void *app_data))
3732264Sjacobs {
3742264Sjacobs 	papi_status_t result = PAPI_OK;
3752264Sjacobs 
3762264Sjacobs 	if (handle != NULL) {
3772264Sjacobs 		service_t *svc = handle;
3782264Sjacobs 		papi_status_t (*f)();
3792264Sjacobs 
3802264Sjacobs 		svc->authCB = authCB;
3812264Sjacobs 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetAuthCB");
3822264Sjacobs 		if (f != NULL)
3832264Sjacobs 			result = f(svc->svc_handle, interposed_auth_callback);
3842264Sjacobs 	} else
3852264Sjacobs 		result = PAPI_BAD_ARGUMENT;
3862264Sjacobs 
3872264Sjacobs 	return (result);
3882264Sjacobs }
3892264Sjacobs 
3902264Sjacobs 
3912264Sjacobs papi_status_t
3922264Sjacobs papiServiceSetAppData(papi_service_t handle, void *app_data)
3932264Sjacobs {
3942264Sjacobs 	papi_status_t result = PAPI_OK;
3952264Sjacobs 
3962264Sjacobs 	if (handle != NULL) {
3972264Sjacobs 		service_t *svc = handle;
3982264Sjacobs 		papi_status_t (*f)();
3992264Sjacobs 
4002264Sjacobs 		svc->app_data = (void *)app_data;
4012264Sjacobs 	} else
4022264Sjacobs 		result = PAPI_BAD_ARGUMENT;
4032264Sjacobs 
4042264Sjacobs 	return (result);
4052264Sjacobs }
4062264Sjacobs 
4072264Sjacobs char *
4082264Sjacobs papiServiceGetServiceName(papi_service_t handle)
4092264Sjacobs {
4102264Sjacobs 	char *result = NULL;
4112264Sjacobs 
4122264Sjacobs 	if (handle != NULL) {
4132264Sjacobs 		service_t *svc = handle;
4142264Sjacobs 		char *(*f)();
4152264Sjacobs 
4162264Sjacobs 		f = (char *(*)())psm_sym(svc, "papiServiceGetServiceName");
4172264Sjacobs 		if (f != NULL)
4182264Sjacobs 			result = f(svc->svc_handle);
4192264Sjacobs 		if (result == NULL)
4202264Sjacobs 			result = svc->name;
4212264Sjacobs 	}
4222264Sjacobs 
4232264Sjacobs 	return (result);
4242264Sjacobs }
4252264Sjacobs 
4262264Sjacobs char *
4272264Sjacobs papiServiceGetUserName(papi_service_t handle)
4282264Sjacobs {
4292264Sjacobs 	char *result = NULL;
4302264Sjacobs 
4312264Sjacobs 	if (handle != NULL) {
4322264Sjacobs 		service_t *svc = handle;
4332264Sjacobs 		char *(*f)();
4342264Sjacobs 
4352264Sjacobs 		f = (char *(*)())psm_sym(svc, "papiServiceGetUserName");
4362264Sjacobs 		if (f != NULL)
4372264Sjacobs 			result = f(svc->svc_handle);
4382264Sjacobs 		if (result == NULL)
4392264Sjacobs 			result = svc->user;
4402264Sjacobs 	}
4412264Sjacobs 
4422264Sjacobs 	return (result);
4432264Sjacobs }
4442264Sjacobs 
4452264Sjacobs char *
4462264Sjacobs papiServiceGetPassword(papi_service_t handle)
4472264Sjacobs {
4482264Sjacobs 	char *result = NULL;
4492264Sjacobs 
4502264Sjacobs 	if (handle != NULL) {
4512264Sjacobs 		service_t *svc = handle;
4522264Sjacobs 		char *(*f)();
4532264Sjacobs 
4542264Sjacobs 		f = (char *(*)())psm_sym(svc, "papiServiceGetPassword");
4552264Sjacobs 		if (f != NULL)
4562264Sjacobs 			result = f(svc->svc_handle);
4572264Sjacobs 		if (result == NULL)
4582264Sjacobs 			result = svc->password;
4592264Sjacobs 	}
4602264Sjacobs 
4612264Sjacobs 	return (result);
4622264Sjacobs }
4632264Sjacobs 
4642264Sjacobs papi_encryption_t
4652264Sjacobs papiServiceGetEncryption(papi_service_t handle)
4662264Sjacobs {
4672264Sjacobs 	papi_encryption_t result = PAPI_ENCRYPT_NEVER;
4682264Sjacobs 
4692264Sjacobs 	if (handle != NULL) {
4702264Sjacobs 		service_t *svc = handle;
4712264Sjacobs 		papi_encryption_t (*f)();
4722264Sjacobs 
4732264Sjacobs 		f = (papi_encryption_t (*)())psm_sym(svc,
4742264Sjacobs 						"papiServiceGetEncryption");
4752264Sjacobs 		if (f != NULL)
4762264Sjacobs 			result = f(svc->svc_handle);
4772264Sjacobs 		if (result == PAPI_ENCRYPT_NEVER)
4782264Sjacobs 			result = svc->encryption;
4792264Sjacobs 	}
4802264Sjacobs 
4812264Sjacobs 	return (result);
4822264Sjacobs }
4832264Sjacobs 
4842264Sjacobs void *
4852264Sjacobs papiServiceGetAppData(papi_service_t handle)
4862264Sjacobs {
4872264Sjacobs 	void *result = NULL;
4882264Sjacobs 	service_t *svc = handle;
4892264Sjacobs 
4902264Sjacobs 	if (handle != NULL)
4912264Sjacobs 		result = svc->app_data;
4922264Sjacobs 
4932264Sjacobs 	return (result);
4942264Sjacobs }
4952264Sjacobs 
4962264Sjacobs papi_attribute_t **
4972264Sjacobs papiServiceGetAttributeList(papi_service_t handle)
4982264Sjacobs {
4992264Sjacobs 	papi_attribute_t **result = NULL;
5002264Sjacobs 	service_t *svc = handle;
5012264Sjacobs 
5022264Sjacobs 	if (handle != NULL) {
5032264Sjacobs 		papi_attribute_t **(*f)();
5042264Sjacobs 
5052264Sjacobs 		if (svc->so_handle == NULL) {
5062264Sjacobs 			char *uri = default_service_uri(DEFAULT_SERVICE_URI);
5072264Sjacobs 
5082264Sjacobs 			if (service_connect(svc, uri) != PAPI_OK)
5092264Sjacobs 				return (NULL);
5102264Sjacobs 		}
5112264Sjacobs 
5122264Sjacobs 		f = (papi_attribute_t **(*)())psm_sym(svc,
5132264Sjacobs 					"papiServiceGetAttributeList");
5142264Sjacobs 		if (f != NULL)
5152264Sjacobs 			result = f(svc->svc_handle);
5162264Sjacobs 	} else
5172264Sjacobs 		result = svc->attributes;
5182264Sjacobs 
5192264Sjacobs 	return (result);
5202264Sjacobs }
5212264Sjacobs 
5222264Sjacobs char *
5232264Sjacobs papiServiceGetStatusMessage(papi_service_t handle)
5242264Sjacobs {
5252264Sjacobs 	char *result = NULL;
5262264Sjacobs 	service_t *svc = handle;
5272264Sjacobs 
5282264Sjacobs 	if (handle != NULL) {
5292264Sjacobs 		char *(*f)();
5302264Sjacobs 
5312264Sjacobs 		f = (char *(*)())psm_sym(svc, "papiServiceGetStatusMessage");
5322264Sjacobs 		if (f != NULL)
5332264Sjacobs 			result = f(svc->svc_handle);
5342264Sjacobs 	}
5352264Sjacobs 	if (result == NULL) {
5362264Sjacobs 		papiAttributeListGetString(svc->attributes, NULL,
5372264Sjacobs 					"detailed-status-message", &result);
5382264Sjacobs 	}
5392264Sjacobs 
5402264Sjacobs 	return (result);
5412264Sjacobs }
5422264Sjacobs 
5432264Sjacobs void
5442264Sjacobs detailed_error(service_t *svc, char *fmt, ...)
5452264Sjacobs {
5462264Sjacobs 	if ((svc != NULL) && (fmt != NULL)) {
5472264Sjacobs 		va_list ap;
5482264Sjacobs 		size_t size;
5492264Sjacobs 		char *message = alloca(BUFSIZ);
5502264Sjacobs 
5512264Sjacobs 		va_start(ap, fmt);
5522264Sjacobs 		/*
5532264Sjacobs 		 * fill in the message.  If the buffer is too small, allocate
5542264Sjacobs 		 * one that is large enough and fill it in.
5552264Sjacobs 		 */
5562264Sjacobs 		if ((size = vsnprintf(message, BUFSIZ, fmt, ap)) >= BUFSIZ)
5572264Sjacobs 			if ((message = alloca(size)) != NULL)
5582264Sjacobs 				vsnprintf(message, size, fmt, ap);
5592264Sjacobs 		va_end(ap);
5602264Sjacobs 
5612264Sjacobs 		papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
5622264Sjacobs 					"detailed-status-message", message);
5632264Sjacobs #ifdef DEBUG
5642264Sjacobs 		fprintf(stderr, "detailed_error(%s)\n", message);
5652264Sjacobs #endif
5662264Sjacobs 	}
5672264Sjacobs }
568