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: stable/10/sys/libkern/iconv.c 330512 2018-03-05 16:00:05Z dab $"); 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"); 46227293Sedstatic 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); 87236899Smjg TAILQ_FOREACH(csp, &iconv_cslist, cp_link) { 88236899Smjg if (csp->cp_refcount) { 89236899Smjg sx_xunlock(&iconv_lock); 9075332Sbp return EBUSY; 91236899Smjg } 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{ 138235712Skevlo dcp->refs--; 13975332Sbp if (dcp->refs > 1) { 14075332Sbp ICDEBUG("converter have %d referenses left\n", dcp->refs); 14175332Sbp return EBUSY; 14275332Sbp } 14375332Sbp TAILQ_REMOVE(&iconv_converters, dcp, cc_link); 14475332Sbp kobj_class_free((struct kobj_class*)dcp); 14575332Sbp return 0; 14675332Sbp} 14775332Sbp 14875332Sbpstatic int 14975332Sbpiconv_lookupconv(const char *name, struct iconv_converter_class **dcpp) 15075332Sbp{ 15175332Sbp struct iconv_converter_class *dcp; 15275332Sbp 15375332Sbp TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { 15475332Sbp if (name == NULL) 15575332Sbp continue; 15675332Sbp if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) { 15775332Sbp if (dcpp) 15875332Sbp *dcpp = dcp; 15975332Sbp return 0; 16075332Sbp } 16175332Sbp } 16275332Sbp return ENOENT; 16375332Sbp} 16475332Sbp 16575332Sbpstatic int 16675332Sbpiconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp) 16775332Sbp{ 16875332Sbp struct iconv_cspair *csp; 16975332Sbp 17075332Sbp TAILQ_FOREACH(csp, &iconv_cslist, cp_link) { 171267980Sjhb if (strcasecmp(csp->cp_to, to) == 0 && 172267980Sjhb strcasecmp(csp->cp_from, from) == 0) { 17375332Sbp if (cspp) 17475332Sbp *cspp = csp; 17575332Sbp return 0; 17675332Sbp } 17775332Sbp } 17875332Sbp return ENOENT; 17975332Sbp} 18075332Sbp 18175332Sbpstatic int 18275332Sbpiconv_register_cspair(const char *to, const char *from, 18375332Sbp struct iconv_converter_class *dcp, void *data, 18475332Sbp struct iconv_cspair **cspp) 18575332Sbp{ 18675332Sbp struct iconv_cspair *csp; 18775332Sbp char *cp; 18875332Sbp int csize, ucsto, ucsfrom; 18975332Sbp 19075332Sbp if (iconv_lookupcs(to, from, NULL) == 0) 19175332Sbp return EEXIST; 19275332Sbp csize = sizeof(*csp); 19375332Sbp ucsto = strcmp(to, iconv_unicode_string) == 0; 19475332Sbp if (!ucsto) 19575332Sbp csize += strlen(to) + 1; 19675332Sbp ucsfrom = strcmp(from, iconv_unicode_string) == 0; 19775332Sbp if (!ucsfrom) 19875332Sbp csize += strlen(from) + 1; 199111119Simp csp = malloc(csize, M_ICONV, M_WAITOK); 20075332Sbp bzero(csp, csize); 20175332Sbp csp->cp_id = iconv_csid++; 20275332Sbp csp->cp_dcp = dcp; 20375332Sbp cp = (char*)(csp + 1); 20475332Sbp if (!ucsto) { 20575332Sbp strcpy(cp, to); 20675332Sbp csp->cp_to = cp; 20775332Sbp cp += strlen(cp) + 1; 20875332Sbp } else 20975332Sbp csp->cp_to = iconv_unicode_string; 21075332Sbp if (!ucsfrom) { 21175332Sbp strcpy(cp, from); 21275332Sbp csp->cp_from = cp; 21375332Sbp } else 21475332Sbp csp->cp_from = iconv_unicode_string; 21575332Sbp csp->cp_data = data; 21675332Sbp 21775332Sbp TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link); 21875332Sbp *cspp = csp; 21975332Sbp return 0; 22075332Sbp} 22175332Sbp 22275332Sbpstatic void 22375332Sbpiconv_unregister_cspair(struct iconv_cspair *csp) 22475332Sbp{ 22575332Sbp TAILQ_REMOVE(&iconv_cslist, csp, cp_link); 22675332Sbp if (csp->cp_data) 22775332Sbp free(csp->cp_data, M_ICONVDATA); 22875332Sbp free(csp, M_ICONV); 22975332Sbp} 23075332Sbp 23175332Sbp/* 23275332Sbp * Lookup and create an instance of converter. 23375332Sbp * Currently this layer didn't have associated 'instance' structure 23475332Sbp * to avoid unnesessary memory allocation. 23575332Sbp */ 23675332Sbpint 23775332Sbpiconv_open(const char *to, const char *from, void **handle) 23875332Sbp{ 23975332Sbp struct iconv_cspair *csp, *cspfrom, *cspto; 24075332Sbp struct iconv_converter_class *dcp; 24175332Sbp const char *cnvname; 24275332Sbp int error; 24375332Sbp 24475332Sbp /* 24575332Sbp * First, lookup fully qualified cspairs 24675332Sbp */ 24775332Sbp error = iconv_lookupcs(to, from, &csp); 24875332Sbp if (error == 0) 24975332Sbp return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle); 25075332Sbp 25175332Sbp /* 25275332Sbp * Well, nothing found. Now try to construct a composite conversion 25375332Sbp * ToDo: add a 'capability' field to converter 25475332Sbp */ 25575332Sbp TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { 25675332Sbp cnvname = ICONV_CONVERTER_NAME(dcp); 25775332Sbp if (cnvname == NULL) 25875332Sbp continue; 25975332Sbp error = iconv_lookupcs(cnvname, from, &cspfrom); 26075332Sbp if (error) 26175332Sbp continue; 26275332Sbp error = iconv_lookupcs(to, cnvname, &cspto); 26375332Sbp if (error) 26475332Sbp continue; 26575332Sbp /* 26675332Sbp * Fine, we're found a pair which can be combined together 26775332Sbp */ 26875332Sbp return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle); 26975332Sbp } 27075332Sbp return ENOENT; 27175332Sbp} 27275332Sbp 27375332Sbpint 27475332Sbpiconv_close(void *handle) 27575332Sbp{ 27675332Sbp return ICONV_CONVERTER_CLOSE(handle); 27775332Sbp} 27875332Sbp 27975332Sbpint 28075332Sbpiconv_conv(void *handle, const char **inbuf, 28175332Sbp size_t *inbytesleft, char **outbuf, size_t *outbytesleft) 28275332Sbp{ 283120492Sfjoe return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0); 28475332Sbp} 28575332Sbp 286120492Sfjoeint 287120492Sfjoeiconv_conv_case(void *handle, const char **inbuf, 288120492Sfjoe size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype) 289120492Sfjoe{ 290120492Sfjoe return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype); 291120492Sfjoe} 292120492Sfjoe 293120492Sfjoeint 294120492Sfjoeiconv_convchr(void *handle, const char **inbuf, 295120492Sfjoe size_t *inbytesleft, char **outbuf, size_t *outbytesleft) 296120492Sfjoe{ 297120492Sfjoe return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0); 298120492Sfjoe} 299120492Sfjoe 300120492Sfjoeint 301120492Sfjoeiconv_convchr_case(void *handle, const char **inbuf, 302120492Sfjoe size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype) 303120492Sfjoe{ 304120492Sfjoe return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype); 305120492Sfjoe} 306120492Sfjoe 307194638Sdelphijint 308194638Sdelphijtowlower(int c, void *handle) 309194638Sdelphij{ 310194638Sdelphij return ICONV_CONVERTER_TOLOWER(handle, c); 311194638Sdelphij} 312194638Sdelphij 313194638Sdelphijint 314194638Sdelphijtowupper(int c, void *handle) 315194638Sdelphij{ 316194638Sdelphij return ICONV_CONVERTER_TOUPPER(handle, c); 317194638Sdelphij} 318194638Sdelphij 31975332Sbp/* 32075332Sbp * Give a list of loaded converters. Each name terminated with 0. 32175332Sbp * An empty string terminates the list. 32275332Sbp */ 32375332Sbpstatic int 32475332Sbpiconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS) 32575332Sbp{ 32675332Sbp struct iconv_converter_class *dcp; 32775332Sbp const char *name; 32875332Sbp char spc; 32975332Sbp int error; 33075332Sbp 33175332Sbp error = 0; 332185652Sjhb sx_slock(&iconv_lock); 33375332Sbp TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { 33475332Sbp name = ICONV_CONVERTER_NAME(dcp); 33575332Sbp if (name == NULL) 33675332Sbp continue; 33775332Sbp error = SYSCTL_OUT(req, name, strlen(name) + 1); 33875332Sbp if (error) 33975332Sbp break; 34075332Sbp } 341185652Sjhb sx_sunlock(&iconv_lock); 34275332Sbp if (error) 34375332Sbp return error; 34475332Sbp spc = 0; 34575332Sbp error = SYSCTL_OUT(req, &spc, sizeof(spc)); 34675332Sbp return error; 34775332Sbp} 34875332Sbp 34975332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE, 35075332Sbp NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters"); 35175332Sbp 35275332Sbp/* 35375332Sbp * List all available charset pairs. 35475332Sbp */ 35575332Sbpstatic int 35675332Sbpiconv_sysctl_cslist(SYSCTL_HANDLER_ARGS) 35775332Sbp{ 35875332Sbp struct iconv_cspair *csp; 35975332Sbp struct iconv_cspair_info csi; 36075332Sbp int error; 36175332Sbp 36275332Sbp error = 0; 36375332Sbp bzero(&csi, sizeof(csi)); 36475332Sbp csi.cs_version = ICONV_CSPAIR_INFO_VER; 365185652Sjhb sx_slock(&iconv_lock); 36675332Sbp TAILQ_FOREACH(csp, &iconv_cslist, cp_link) { 36775332Sbp csi.cs_id = csp->cp_id; 36875332Sbp csi.cs_refcount = csp->cp_refcount; 36975332Sbp csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0; 37075332Sbp strcpy(csi.cs_to, csp->cp_to); 37175332Sbp strcpy(csi.cs_from, csp->cp_from); 37275332Sbp error = SYSCTL_OUT(req, &csi, sizeof(csi)); 37375332Sbp if (error) 37475332Sbp break; 37575332Sbp } 376185652Sjhb sx_sunlock(&iconv_lock); 37775332Sbp return error; 37875332Sbp} 37975332Sbp 38075332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE, 38175332Sbp NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs"); 38275332Sbp 383227650Skevloint 384227650Skevloiconv_add(const char *converter, const char *to, const char *from) 385227650Skevlo{ 386227650Skevlo struct iconv_converter_class *dcp; 387227650Skevlo struct iconv_cspair *csp; 388227650Skevlo 389227650Skevlo if (iconv_lookupconv(converter, &dcp) != 0) 390227650Skevlo return EINVAL; 391227650Skevlo 392227650Skevlo return iconv_register_cspair(to, from, dcp, NULL, &csp); 393227650Skevlo} 394227650Skevlo 39575332Sbp/* 39675332Sbp * Add new charset pair 39775332Sbp */ 39875332Sbpstatic int 39975332Sbpiconv_sysctl_add(SYSCTL_HANDLER_ARGS) 40075332Sbp{ 40175332Sbp struct iconv_converter_class *dcp; 40275332Sbp struct iconv_cspair *csp; 40375332Sbp struct iconv_add_in din; 40475332Sbp struct iconv_add_out dout; 40575332Sbp int error; 40675332Sbp 40775332Sbp error = SYSCTL_IN(req, &din, sizeof(din)); 40875332Sbp if (error) 40975332Sbp return error; 41075332Sbp if (din.ia_version != ICONV_ADD_VER) 41175332Sbp return EINVAL; 41275332Sbp if (din.ia_datalen > ICONV_CSMAXDATALEN) 41375332Sbp return EINVAL; 414330512Sdab if (strnlen(din.ia_from, sizeof(din.ia_from)) >= ICONV_CSNMAXLEN) 415149415Simura return EINVAL; 416330512Sdab if (strnlen(din.ia_to, sizeof(din.ia_to)) >= ICONV_CSNMAXLEN) 417149415Simura return EINVAL; 418330512Sdab if (strnlen(din.ia_converter, sizeof(din.ia_converter)) >= ICONV_CNVNMAXLEN) 419149415Simura return EINVAL; 42075332Sbp if (iconv_lookupconv(din.ia_converter, &dcp) != 0) 42175332Sbp return EINVAL; 422185652Sjhb sx_xlock(&iconv_lock); 42375332Sbp error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp); 424185652Sjhb if (error) { 425185652Sjhb sx_xunlock(&iconv_lock); 42675332Sbp return error; 427185652Sjhb } 42875332Sbp if (din.ia_datalen) { 429111119Simp csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK); 43075332Sbp error = copyin(din.ia_data, csp->cp_data, din.ia_datalen); 43175332Sbp if (error) 43275332Sbp goto bad; 43375332Sbp } 43475332Sbp dout.ia_csid = csp->cp_id; 43575332Sbp error = SYSCTL_OUT(req, &dout, sizeof(dout)); 43675332Sbp if (error) 43775332Sbp goto bad; 438185652Sjhb sx_xunlock(&iconv_lock); 439120492Sfjoe ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen); 44075332Sbp return 0; 44175332Sbpbad: 44275332Sbp iconv_unregister_cspair(csp); 443185652Sjhb sx_xunlock(&iconv_lock); 44475332Sbp return error; 44575332Sbp} 44675332Sbp 44775332SbpSYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE, 44875332Sbp NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair"); 44975332Sbp 45075332Sbp/* 45175332Sbp * Default stubs for converters 45275332Sbp */ 45375332Sbpint 45475332Sbpiconv_converter_initstub(struct iconv_converter_class *dp) 45575332Sbp{ 45675332Sbp return 0; 45775332Sbp} 45875332Sbp 45975332Sbpint 46075332Sbpiconv_converter_donestub(struct iconv_converter_class *dp) 46175332Sbp{ 46275332Sbp return 0; 46375332Sbp} 46475332Sbp 46575332Sbpint 466194638Sdelphijiconv_converter_tolowerstub(int c, void *handle) 467194638Sdelphij{ 468194638Sdelphij return (c); 469194638Sdelphij} 470194638Sdelphij 471194638Sdelphijint 47275332Sbpiconv_converter_handler(module_t mod, int type, void *data) 47375332Sbp{ 47475332Sbp struct iconv_converter_class *dcp = data; 47575332Sbp int error; 47675332Sbp 47775332Sbp switch (type) { 47875332Sbp case MOD_LOAD: 479185652Sjhb sx_xlock(&iconv_lock); 48075332Sbp error = iconv_register_converter(dcp); 481185652Sjhb if (error) { 482185652Sjhb sx_xunlock(&iconv_lock); 48375332Sbp break; 484185652Sjhb } 48575332Sbp error = ICONV_CONVERTER_INIT(dcp); 48675332Sbp if (error) 48775332Sbp iconv_unregister_converter(dcp); 488185652Sjhb sx_xunlock(&iconv_lock); 48975332Sbp break; 49075332Sbp case MOD_UNLOAD: 491185652Sjhb sx_xlock(&iconv_lock); 49275332Sbp ICONV_CONVERTER_DONE(dcp); 49375332Sbp error = iconv_unregister_converter(dcp); 494185652Sjhb sx_xunlock(&iconv_lock); 49575332Sbp break; 49675332Sbp default: 49775332Sbp error = EINVAL; 49875332Sbp } 49975332Sbp return error; 50075332Sbp} 50175332Sbp 50275332Sbp/* 503120492Sfjoe * Common used functions (don't use with unicode) 50475332Sbp */ 50575332Sbpchar * 50675332Sbpiconv_convstr(void *handle, char *dst, const char *src) 50775332Sbp{ 50875332Sbp char *p = dst; 509104568Smux size_t inlen, outlen; 510104568Smux int error; 51175332Sbp 51275332Sbp if (handle == NULL) { 51375332Sbp strcpy(dst, src); 51475332Sbp return dst; 51575332Sbp } 516148342Simura inlen = outlen = strlen(src); 51775332Sbp error = iconv_conv(handle, NULL, NULL, &p, &outlen); 51875332Sbp if (error) 51975332Sbp return NULL; 52075332Sbp error = iconv_conv(handle, &src, &inlen, &p, &outlen); 52175332Sbp if (error) 52275332Sbp return NULL; 52375332Sbp *p = 0; 52475332Sbp return dst; 52575332Sbp} 52675332Sbp 52775332Sbpvoid * 52875332Sbpiconv_convmem(void *handle, void *dst, const void *src, int size) 52975332Sbp{ 53075332Sbp const char *s = src; 53175332Sbp char *d = dst; 532104568Smux size_t inlen, outlen; 533104568Smux int error; 53475332Sbp 53575332Sbp if (size == 0) 53675332Sbp return dst; 53775332Sbp if (handle == NULL) { 53875332Sbp memcpy(dst, src, size); 53975332Sbp return dst; 54075332Sbp } 541148342Simura inlen = outlen = size; 54275332Sbp error = iconv_conv(handle, NULL, NULL, &d, &outlen); 54375332Sbp if (error) 54475332Sbp return NULL; 54575332Sbp error = iconv_conv(handle, &s, &inlen, &d, &outlen); 54675332Sbp if (error) 54775332Sbp return NULL; 54875332Sbp return dst; 54975332Sbp} 55075332Sbp 55175332Sbpint 55275332Sbpiconv_lookupcp(char **cpp, const char *s) 55375332Sbp{ 55475332Sbp if (cpp == NULL) { 555235711Skevlo ICDEBUG("warning a NULL list passed\n", ""); 55675332Sbp return ENOENT; 55775332Sbp } 55875332Sbp for (; *cpp; cpp++) 55975332Sbp if (strcmp(*cpp, s) == 0) 56075332Sbp return 0; 56175332Sbp return ENOENT; 56275332Sbp} 563120492Sfjoe 564120492Sfjoe/* 565120492Sfjoe * Return if fsname is in use of not 566120492Sfjoe */ 567120492Sfjoeint 568120492Sfjoeiconv_vfs_refcount(const char *fsname) 569120492Sfjoe{ 570120492Sfjoe struct vfsconf *vfsp; 571120492Sfjoe 572132710Sphk vfsp = vfs_byname(fsname); 573132710Sphk if (vfsp != NULL && vfsp->vfc_refcount > 0) 574132710Sphk return (EBUSY); 575120492Sfjoe return (0); 576120492Sfjoe} 577