1139815Simp/*-
2206361Sjoel * Copyright (c) 2000-2001 Boris Popov
375332Sbp * All rights reserved.
475332Sbp *
575332Sbp * Redistribution and use in source and binary forms, with or without
675332Sbp * modification, are permitted provided that the following conditions
775332Sbp * are met:
875332Sbp * 1. Redistributions of source code must retain the above copyright
975332Sbp *    notice, this list of conditions and the following disclaimer.
1075332Sbp * 2. Redistributions in binary form must reproduce the above copyright
1175332Sbp *    notice, this list of conditions and the following disclaimer in the
1275332Sbp *    documentation and/or other materials provided with the distribution.
1375332Sbp *
1475332Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1575332Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1675332Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1775332Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1875332Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1975332Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2075332Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2175332Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2275332Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2375332Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2475332Sbp * SUCH DAMAGE.
2575332Sbp */
26116189Sobrien
27116189Sobrien#include <sys/cdefs.h>
28116189Sobrien__FBSDID("$FreeBSD$");
29116189Sobrien
3075332Sbp#include <sys/param.h>
3175332Sbp#include <sys/systm.h>
3275332Sbp#include <sys/kernel.h>
3375332Sbp#include <sys/iconv.h>
3475332Sbp#include <sys/malloc.h>
35120492Sfjoe#include <sys/mount.h>
36185652Sjhb#include <sys/sx.h>
37120492Sfjoe#include <sys/syslog.h>
3875332Sbp
3975332Sbp#include "iconv_converter_if.h"
4075332Sbp
4175332SbpSYSCTL_DECL(_kern_iconv);
4275332Sbp
4375332SbpSYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface");
4475332Sbp
45151897SrwatsonMALLOC_DEFINE(M_ICONV, "iconv", "ICONV structures");
46249132Smavstatic MALLOC_DEFINE(M_ICONVDATA, "iconv_data", "ICONV data");
4775332Sbp
48120492SfjoeMODULE_VERSION(libiconv, 2);
4975332Sbp
50185652Sjhbstatic struct sx iconv_lock;
51185652Sjhb
5275332Sbp#ifdef notnow
5375332Sbp/*
5475332Sbp * iconv converter instance
5575332Sbp */
5675332Sbpstruct iconv_converter {
5775332Sbp	KOBJ_FIELDS;
5875332Sbp	void *			c_data;
5975332Sbp};
6075332Sbp#endif
6175332Sbp
6275332Sbpstruct sysctl_oid *iconv_oid_hook = &sysctl___kern_iconv;
6375332Sbp
6475332Sbp/*
6575332Sbp * List of loaded converters
6675332Sbp */
6775332Sbpstatic TAILQ_HEAD(iconv_converter_list, iconv_converter_class)
6875332Sbp    iconv_converters = TAILQ_HEAD_INITIALIZER(iconv_converters);
6975332Sbp
7075332Sbp/*
7175332Sbp * List of supported/loaded charsets pairs
7275332Sbp */
7375332Sbpstatic TAILQ_HEAD(, iconv_cspair)
7475332Sbp    iconv_cslist = TAILQ_HEAD_INITIALIZER(iconv_cslist);
7575332Sbpstatic int iconv_csid = 1;
7675332Sbp
7775332Sbpstatic char iconv_unicode_string[] = "unicode";	/* save eight bytes when possible */
7875332Sbp
7975332Sbpstatic void iconv_unregister_cspair(struct iconv_cspair *csp);
8075332Sbp
8175332Sbpstatic int
8275332Sbpiconv_mod_unload(void)
8375332Sbp{
8475332Sbp	struct iconv_cspair *csp;
8575332Sbp
86185652Sjhb	sx_xlock(&iconv_lock);
87245149Skevlo	TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
88245149Skevlo		if (csp->cp_refcount) {
89245149Skevlo			sx_xunlock(&iconv_lock);
9075332Sbp			return EBUSY;
91245149Skevlo		}
92185652Sjhb	}
93185652Sjhb
94185652Sjhb	while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL)
9575332Sbp		iconv_unregister_cspair(csp);
96185652Sjhb	sx_xunlock(&iconv_lock);
97185652Sjhb	sx_destroy(&iconv_lock);
9875332Sbp	return 0;
9975332Sbp}
10075332Sbp
10175332Sbpstatic int
10275332Sbpiconv_mod_handler(module_t mod, int type, void *data)
10375332Sbp{
10475332Sbp	int error;
10575332Sbp
10675332Sbp	switch (type) {
10775332Sbp	    case MOD_LOAD:
10875332Sbp		error = 0;
109185652Sjhb		sx_init(&iconv_lock, "iconv");
11075332Sbp		break;
11175332Sbp	    case MOD_UNLOAD:
11275332Sbp		error = iconv_mod_unload();
11375332Sbp		break;
11475332Sbp	    default:
11575332Sbp		error = EINVAL;
11675332Sbp	}
11775332Sbp	return error;
11875332Sbp}
11975332Sbp
12075332Sbpstatic moduledata_t iconv_mod = {
12175332Sbp	"iconv", iconv_mod_handler, NULL
12275332Sbp};
12375332Sbp
12475332SbpDECLARE_MODULE(iconv, iconv_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
12575332Sbp
12675332Sbpstatic int
12775332Sbpiconv_register_converter(struct iconv_converter_class *dcp)
12875332Sbp{
12975332Sbp	kobj_class_compile((struct kobj_class*)dcp);
13075332Sbp	dcp->refs++;
13175332Sbp	TAILQ_INSERT_TAIL(&iconv_converters, dcp, cc_link);
13275332Sbp	return 0;
13375332Sbp}
13475332Sbp
13575332Sbpstatic int
13675332Sbpiconv_unregister_converter(struct iconv_converter_class *dcp)
13775332Sbp{
13875332Sbp	if (dcp->refs > 1) {
13975332Sbp		ICDEBUG("converter have %d referenses left\n", dcp->refs);
14075332Sbp		return EBUSY;
14175332Sbp	}
14275332Sbp	TAILQ_REMOVE(&iconv_converters, dcp, cc_link);
14375332Sbp	kobj_class_free((struct kobj_class*)dcp);
14475332Sbp	return 0;
14575332Sbp}
14675332Sbp
14775332Sbpstatic int
14875332Sbpiconv_lookupconv(const char *name, struct iconv_converter_class **dcpp)
14975332Sbp{
15075332Sbp	struct iconv_converter_class *dcp;
15175332Sbp
15275332Sbp	TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
15375332Sbp		if (name == NULL)
15475332Sbp			continue;
15575332Sbp		if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) {
15675332Sbp			if (dcpp)
15775332Sbp				*dcpp = dcp;
15875332Sbp			return 0;
15975332Sbp		}
16075332Sbp	}
16175332Sbp	return ENOENT;
16275332Sbp}
16375332Sbp
16475332Sbpstatic int
16575332Sbpiconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp)
16675332Sbp{
16775332Sbp	struct iconv_cspair *csp;
16875332Sbp
16975332Sbp	TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
17075332Sbp		if (strcmp(csp->cp_to, to) == 0 &&
17175332Sbp		    strcmp(csp->cp_from, from) == 0) {
17275332Sbp			if (cspp)
17375332Sbp				*cspp = csp;
17475332Sbp			return 0;
17575332Sbp		}
17675332Sbp	}
17775332Sbp	return ENOENT;
17875332Sbp}
17975332Sbp
18075332Sbpstatic int
18175332Sbpiconv_register_cspair(const char *to, const char *from,
18275332Sbp	struct iconv_converter_class *dcp, void *data,
18375332Sbp	struct iconv_cspair **cspp)
18475332Sbp{
18575332Sbp	struct iconv_cspair *csp;
18675332Sbp	char *cp;
18775332Sbp	int csize, ucsto, ucsfrom;
18875332Sbp
18975332Sbp	if (iconv_lookupcs(to, from, NULL) == 0)
19075332Sbp		return EEXIST;
19175332Sbp	csize = sizeof(*csp);
19275332Sbp	ucsto = strcmp(to, iconv_unicode_string) == 0;
19375332Sbp	if (!ucsto)
19475332Sbp		csize += strlen(to) + 1;
19575332Sbp	ucsfrom = strcmp(from, iconv_unicode_string) == 0;
19675332Sbp	if (!ucsfrom)
19775332Sbp		csize += strlen(from) + 1;
198111119Simp	csp = malloc(csize, M_ICONV, M_WAITOK);
19975332Sbp	bzero(csp, csize);
20075332Sbp	csp->cp_id = iconv_csid++;
20175332Sbp	csp->cp_dcp = dcp;
20275332Sbp	cp = (char*)(csp + 1);
20375332Sbp	if (!ucsto) {
20475332Sbp		strcpy(cp, to);
20575332Sbp		csp->cp_to = cp;
20675332Sbp		cp += strlen(cp) + 1;
20775332Sbp	} else
20875332Sbp		csp->cp_to = iconv_unicode_string;
20975332Sbp	if (!ucsfrom) {
21075332Sbp		strcpy(cp, from);
21175332Sbp		csp->cp_from = cp;
21275332Sbp	} else
21375332Sbp		csp->cp_from = iconv_unicode_string;
21475332Sbp	csp->cp_data = data;
21575332Sbp
21675332Sbp	TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link);
21775332Sbp	*cspp = csp;
21875332Sbp	return 0;
21975332Sbp}
22075332Sbp
22175332Sbpstatic void
22275332Sbpiconv_unregister_cspair(struct iconv_cspair *csp)
22375332Sbp{
22475332Sbp	TAILQ_REMOVE(&iconv_cslist, csp, cp_link);
22575332Sbp	if (csp->cp_data)
22675332Sbp		free(csp->cp_data, M_ICONVDATA);
22775332Sbp	free(csp, M_ICONV);
22875332Sbp}
22975332Sbp
23075332Sbp/*
23175332Sbp * Lookup and create an instance of converter.
23275332Sbp * Currently this layer didn't have associated 'instance' structure
23375332Sbp * to avoid unnesessary memory allocation.
23475332Sbp */
23575332Sbpint
23675332Sbpiconv_open(const char *to, const char *from, void **handle)
23775332Sbp{
23875332Sbp	struct iconv_cspair *csp, *cspfrom, *cspto;
23975332Sbp	struct iconv_converter_class *dcp;
24075332Sbp	const char *cnvname;
24175332Sbp	int error;
24275332Sbp
24375332Sbp	/*
24475332Sbp	 * First, lookup fully qualified cspairs
24575332Sbp	 */
24675332Sbp	error = iconv_lookupcs(to, from, &csp);
24775332Sbp	if (error == 0)
24875332Sbp		return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle);
24975332Sbp
25075332Sbp	/*
25175332Sbp	 * Well, nothing found. Now try to construct a composite conversion
25275332Sbp	 * ToDo: add a 'capability' field to converter
25375332Sbp	 */
25475332Sbp	TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
25575332Sbp		cnvname = ICONV_CONVERTER_NAME(dcp);
25675332Sbp		if (cnvname == NULL)
25775332Sbp			continue;
25875332Sbp		error = iconv_lookupcs(cnvname, from, &cspfrom);
25975332Sbp		if (error)
26075332Sbp			continue;
26175332Sbp		error = iconv_lookupcs(to, cnvname, &cspto);
26275332Sbp		if (error)
26375332Sbp			continue;
26475332Sbp		/*
26575332Sbp		 * Fine, we're found a pair which can be combined together
26675332Sbp		 */
26775332Sbp		return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle);
26875332Sbp	}
26975332Sbp	return ENOENT;
27075332Sbp}
27175332Sbp
27275332Sbpint
27375332Sbpiconv_close(void *handle)
27475332Sbp{
27575332Sbp	return ICONV_CONVERTER_CLOSE(handle);
27675332Sbp}
27775332Sbp
27875332Sbpint
27975332Sbpiconv_conv(void *handle, const char **inbuf,
28075332Sbp	size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
28175332Sbp{
282120492Sfjoe	return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0);
28375332Sbp}
28475332Sbp
285120492Sfjoeint
286120492Sfjoeiconv_conv_case(void *handle, const char **inbuf,
287120492Sfjoe	size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
288120492Sfjoe{
289120492Sfjoe	return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype);
290120492Sfjoe}
291120492Sfjoe
292120492Sfjoeint
293120492Sfjoeiconv_convchr(void *handle, const char **inbuf,
294120492Sfjoe	size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
295120492Sfjoe{
296120492Sfjoe	return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0);
297120492Sfjoe}
298120492Sfjoe
299120492Sfjoeint
300120492Sfjoeiconv_convchr_case(void *handle, const char **inbuf,
301120492Sfjoe	size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
302120492Sfjoe{
303120492Sfjoe	return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype);
304120492Sfjoe}
305120492Sfjoe
306194638Sdelphijint
307194638Sdelphijtowlower(int c, void *handle)
308194638Sdelphij{
309194638Sdelphij	return ICONV_CONVERTER_TOLOWER(handle, c);
310194638Sdelphij}
311194638Sdelphij
312194638Sdelphijint
313194638Sdelphijtowupper(int c, void *handle)
314194638Sdelphij{
315194638Sdelphij	return ICONV_CONVERTER_TOUPPER(handle, c);
316194638Sdelphij}
317194638Sdelphij
31875332Sbp/*
31975332Sbp * Give a list of loaded converters. Each name terminated with 0.
32075332Sbp * An empty string terminates the list.
32175332Sbp */
32275332Sbpstatic int
32375332Sbpiconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
32475332Sbp{
32575332Sbp	struct iconv_converter_class *dcp;
32675332Sbp	const char *name;
32775332Sbp	char spc;
32875332Sbp	int error;
32975332Sbp
33075332Sbp	error = 0;
331185652Sjhb	sx_slock(&iconv_lock);
33275332Sbp	TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
33375332Sbp		name = ICONV_CONVERTER_NAME(dcp);
33475332Sbp		if (name == NULL)
33575332Sbp			continue;
33675332Sbp		error = SYSCTL_OUT(req, name, strlen(name) + 1);
33775332Sbp		if (error)
33875332Sbp			break;
33975332Sbp	}
340185652Sjhb	sx_sunlock(&iconv_lock);
34175332Sbp	if (error)
34275332Sbp		return error;
34375332Sbp	spc = 0;
34475332Sbp	error = SYSCTL_OUT(req, &spc, sizeof(spc));
34575332Sbp	return error;
34675332Sbp}
34775332Sbp
34875332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE,
34975332Sbp	    NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters");
35075332Sbp
35175332Sbp/*
35275332Sbp * List all available charset pairs.
35375332Sbp */
35475332Sbpstatic int
35575332Sbpiconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
35675332Sbp{
35775332Sbp	struct iconv_cspair *csp;
35875332Sbp	struct iconv_cspair_info csi;
35975332Sbp	int error;
36075332Sbp
36175332Sbp	error = 0;
36275332Sbp	bzero(&csi, sizeof(csi));
36375332Sbp	csi.cs_version = ICONV_CSPAIR_INFO_VER;
364185652Sjhb	sx_slock(&iconv_lock);
36575332Sbp	TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
36675332Sbp		csi.cs_id = csp->cp_id;
36775332Sbp		csi.cs_refcount = csp->cp_refcount;
36875332Sbp		csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0;
36975332Sbp		strcpy(csi.cs_to, csp->cp_to);
37075332Sbp		strcpy(csi.cs_from, csp->cp_from);
37175332Sbp		error = SYSCTL_OUT(req, &csi, sizeof(csi));
37275332Sbp		if (error)
37375332Sbp			break;
37475332Sbp	}
375185652Sjhb	sx_sunlock(&iconv_lock);
37675332Sbp	return error;
37775332Sbp}
37875332Sbp
37975332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE,
38075332Sbp	    NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs");
38175332Sbp
382230196Skevloint
383230196Skevloiconv_add(const char *converter, const char *to, const char *from)
384230196Skevlo{
385230196Skevlo	struct iconv_converter_class *dcp;
386230196Skevlo	struct iconv_cspair *csp;
387230196Skevlo
388230196Skevlo	if (iconv_lookupconv(converter, &dcp) != 0)
389230196Skevlo		return EINVAL;
390230196Skevlo
391230196Skevlo	return iconv_register_cspair(to, from, dcp, NULL, &csp);
392230196Skevlo}
393230196Skevlo
39475332Sbp/*
39575332Sbp * Add new charset pair
39675332Sbp */
39775332Sbpstatic int
39875332Sbpiconv_sysctl_add(SYSCTL_HANDLER_ARGS)
39975332Sbp{
40075332Sbp	struct iconv_converter_class *dcp;
40175332Sbp	struct iconv_cspair *csp;
40275332Sbp	struct iconv_add_in din;
40375332Sbp	struct iconv_add_out dout;
40475332Sbp	int error;
40575332Sbp
40675332Sbp	error = SYSCTL_IN(req, &din, sizeof(din));
40775332Sbp	if (error)
40875332Sbp		return error;
40975332Sbp	if (din.ia_version != ICONV_ADD_VER)
41075332Sbp		return EINVAL;
41175332Sbp	if (din.ia_datalen > ICONV_CSMAXDATALEN)
41275332Sbp		return EINVAL;
413149415Simura	if (strlen(din.ia_from) >= ICONV_CSNMAXLEN)
414149415Simura		return EINVAL;
415149415Simura	if (strlen(din.ia_to) >= ICONV_CSNMAXLEN)
416149415Simura		return EINVAL;
417149415Simura	if (strlen(din.ia_converter) >= ICONV_CNVNMAXLEN)
418149415Simura		return EINVAL;
41975332Sbp	if (iconv_lookupconv(din.ia_converter, &dcp) != 0)
42075332Sbp		return EINVAL;
421185652Sjhb	sx_xlock(&iconv_lock);
42275332Sbp	error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp);
423185652Sjhb	if (error) {
424185652Sjhb		sx_xunlock(&iconv_lock);
42575332Sbp		return error;
426185652Sjhb	}
42775332Sbp	if (din.ia_datalen) {
428111119Simp		csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK);
42975332Sbp		error = copyin(din.ia_data, csp->cp_data, din.ia_datalen);
43075332Sbp		if (error)
43175332Sbp			goto bad;
43275332Sbp	}
43375332Sbp	dout.ia_csid = csp->cp_id;
43475332Sbp	error = SYSCTL_OUT(req, &dout, sizeof(dout));
43575332Sbp	if (error)
43675332Sbp		goto bad;
437185652Sjhb	sx_xunlock(&iconv_lock);
438120492Sfjoe	ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
43975332Sbp	return 0;
44075332Sbpbad:
44175332Sbp	iconv_unregister_cspair(csp);
442185652Sjhb	sx_xunlock(&iconv_lock);
44375332Sbp	return error;
44475332Sbp}
44575332Sbp
44675332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE,
44775332Sbp	    NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair");
44875332Sbp
44975332Sbp/*
45075332Sbp * Default stubs for converters
45175332Sbp */
45275332Sbpint
45375332Sbpiconv_converter_initstub(struct iconv_converter_class *dp)
45475332Sbp{
45575332Sbp	return 0;
45675332Sbp}
45775332Sbp
45875332Sbpint
45975332Sbpiconv_converter_donestub(struct iconv_converter_class *dp)
46075332Sbp{
46175332Sbp	return 0;
46275332Sbp}
46375332Sbp
46475332Sbpint
465194638Sdelphijiconv_converter_tolowerstub(int c, void *handle)
466194638Sdelphij{
467194638Sdelphij	return (c);
468194638Sdelphij}
469194638Sdelphij
470194638Sdelphijint
47175332Sbpiconv_converter_handler(module_t mod, int type, void *data)
47275332Sbp{
47375332Sbp	struct iconv_converter_class *dcp = data;
47475332Sbp	int error;
47575332Sbp
47675332Sbp	switch (type) {
47775332Sbp	    case MOD_LOAD:
478185652Sjhb		sx_xlock(&iconv_lock);
47975332Sbp		error = iconv_register_converter(dcp);
480185652Sjhb		if (error) {
481185652Sjhb			sx_xunlock(&iconv_lock);
48275332Sbp			break;
483185652Sjhb		}
48475332Sbp		error = ICONV_CONVERTER_INIT(dcp);
48575332Sbp		if (error)
48675332Sbp			iconv_unregister_converter(dcp);
487185652Sjhb		sx_xunlock(&iconv_lock);
48875332Sbp		break;
48975332Sbp	    case MOD_UNLOAD:
490185652Sjhb		sx_xlock(&iconv_lock);
49175332Sbp		ICONV_CONVERTER_DONE(dcp);
49275332Sbp		error = iconv_unregister_converter(dcp);
493185652Sjhb		sx_xunlock(&iconv_lock);
49475332Sbp		break;
49575332Sbp	    default:
49675332Sbp		error = EINVAL;
49775332Sbp	}
49875332Sbp	return error;
49975332Sbp}
50075332Sbp
50175332Sbp/*
502120492Sfjoe * Common used functions (don't use with unicode)
50375332Sbp */
50475332Sbpchar *
50575332Sbpiconv_convstr(void *handle, char *dst, const char *src)
50675332Sbp{
50775332Sbp	char *p = dst;
508104568Smux	size_t inlen, outlen;
509104568Smux	int error;
51075332Sbp
51175332Sbp	if (handle == NULL) {
51275332Sbp		strcpy(dst, src);
51375332Sbp		return dst;
51475332Sbp	}
515148342Simura	inlen = outlen = strlen(src);
51675332Sbp	error = iconv_conv(handle, NULL, NULL, &p, &outlen);
51775332Sbp	if (error)
51875332Sbp		return NULL;
51975332Sbp	error = iconv_conv(handle, &src, &inlen, &p, &outlen);
52075332Sbp	if (error)
52175332Sbp		return NULL;
52275332Sbp	*p = 0;
52375332Sbp	return dst;
52475332Sbp}
52575332Sbp
52675332Sbpvoid *
52775332Sbpiconv_convmem(void *handle, void *dst, const void *src, int size)
52875332Sbp{
52975332Sbp	const char *s = src;
53075332Sbp	char *d = dst;
531104568Smux	size_t inlen, outlen;
532104568Smux	int error;
53375332Sbp
53475332Sbp	if (size == 0)
53575332Sbp		return dst;
53675332Sbp	if (handle == NULL) {
53775332Sbp		memcpy(dst, src, size);
53875332Sbp		return dst;
53975332Sbp	}
540148342Simura	inlen = outlen = size;
54175332Sbp	error = iconv_conv(handle, NULL, NULL, &d, &outlen);
54275332Sbp	if (error)
54375332Sbp		return NULL;
54475332Sbp	error = iconv_conv(handle, &s, &inlen, &d, &outlen);
54575332Sbp	if (error)
54675332Sbp		return NULL;
54775332Sbp	return dst;
54875332Sbp}
54975332Sbp
55075332Sbpint
55175332Sbpiconv_lookupcp(char **cpp, const char *s)
55275332Sbp{
55375332Sbp	if (cpp == NULL) {
554100080Smarkm		ICDEBUG("warning a NULL list passed\n", ""); /* XXX ISO variadic								macros cannot
555100080Smarkm								leave out the
556100080Smarkm								variadic args */
55775332Sbp		return ENOENT;
55875332Sbp	}
55975332Sbp	for (; *cpp; cpp++)
56075332Sbp		if (strcmp(*cpp, s) == 0)
56175332Sbp			return 0;
56275332Sbp	return ENOENT;
56375332Sbp}
564120492Sfjoe
565120492Sfjoe/*
566120492Sfjoe * Return if fsname is in use of not
567120492Sfjoe */
568120492Sfjoeint
569120492Sfjoeiconv_vfs_refcount(const char *fsname)
570120492Sfjoe{
571120492Sfjoe	struct vfsconf *vfsp;
572120492Sfjoe
573132710Sphk	vfsp = vfs_byname(fsname);
574132710Sphk	if (vfsp != NULL && vfsp->vfc_refcount > 0)
575132710Sphk		return (EBUSY);
576120492Sfjoe	return (0);
577120492Sfjoe}
578