The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/iconv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2000-2001 Boris Popov
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/iconv.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mount.h>
   38 #include <sys/sx.h>
   39 #include <sys/syslog.h>
   40 
   41 #include "iconv_converter_if.h"
   42 
   43 SYSCTL_DECL(_kern_iconv);
   44 
   45 SYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface");
   46 
   47 MALLOC_DEFINE(M_ICONV, "iconv", "ICONV structures");
   48 static MALLOC_DEFINE(M_ICONVDATA, "iconv_data", "ICONV data");
   49 
   50 MODULE_VERSION(libiconv, 2);
   51 
   52 static struct sx iconv_lock;
   53 
   54 #ifdef notnow
   55 /*
   56  * iconv converter instance
   57  */
   58 struct iconv_converter {
   59         KOBJ_FIELDS;
   60         void *                  c_data;
   61 };
   62 #endif
   63 
   64 struct sysctl_oid *iconv_oid_hook = &sysctl___kern_iconv;
   65 
   66 /*
   67  * List of loaded converters
   68  */
   69 static TAILQ_HEAD(iconv_converter_list, iconv_converter_class)
   70     iconv_converters = TAILQ_HEAD_INITIALIZER(iconv_converters);
   71 
   72 /*
   73  * List of supported/loaded charsets pairs
   74  */
   75 static TAILQ_HEAD(, iconv_cspair)
   76     iconv_cslist = TAILQ_HEAD_INITIALIZER(iconv_cslist);
   77 static int iconv_csid = 1;
   78 
   79 static char iconv_unicode_string[] = "unicode"; /* save eight bytes when possible */
   80 
   81 static void iconv_unregister_cspair(struct iconv_cspair *csp);
   82 
   83 static int
   84 iconv_mod_unload(void)
   85 {
   86         struct iconv_cspair *csp;
   87 
   88         sx_xlock(&iconv_lock);
   89         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
   90                 if (csp->cp_refcount) {
   91                         sx_xunlock(&iconv_lock);
   92                         return EBUSY;
   93                 }
   94         }
   95 
   96         while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL)
   97                 iconv_unregister_cspair(csp);
   98         sx_xunlock(&iconv_lock);
   99         sx_destroy(&iconv_lock);
  100         return 0;
  101 }
  102 
  103 static int
  104 iconv_mod_handler(module_t mod, int type, void *data)
  105 {
  106         int error;
  107 
  108         switch (type) {
  109             case MOD_LOAD:
  110                 error = 0;
  111                 sx_init(&iconv_lock, "iconv");
  112                 break;
  113             case MOD_UNLOAD:
  114                 error = iconv_mod_unload();
  115                 break;
  116             default:
  117                 error = EINVAL;
  118         }
  119         return error;
  120 }
  121 
  122 static moduledata_t iconv_mod = {
  123         "iconv", iconv_mod_handler, NULL
  124 };
  125 
  126 DECLARE_MODULE(iconv, iconv_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  127 
  128 static int
  129 iconv_register_converter(struct iconv_converter_class *dcp)
  130 {
  131         kobj_class_compile((struct kobj_class*)dcp);
  132         dcp->refs++;
  133         TAILQ_INSERT_TAIL(&iconv_converters, dcp, cc_link);
  134         return 0;
  135 }
  136 
  137 static int
  138 iconv_unregister_converter(struct iconv_converter_class *dcp)
  139 {
  140         dcp->refs--;
  141         if (dcp->refs > 1) {
  142                 ICDEBUG("converter has %d references left\n", dcp->refs);
  143                 return EBUSY;
  144         }
  145         TAILQ_REMOVE(&iconv_converters, dcp, cc_link);
  146         kobj_class_free((struct kobj_class*)dcp);
  147         return 0;
  148 }
  149 
  150 static int
  151 iconv_lookupconv(const char *name, struct iconv_converter_class **dcpp)
  152 {
  153         struct iconv_converter_class *dcp;
  154 
  155         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  156                 if (name == NULL)
  157                         continue;
  158                 if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) {
  159                         if (dcpp)
  160                                 *dcpp = dcp;
  161                         return 0;
  162                 }
  163         }
  164         return ENOENT;
  165 }
  166 
  167 static int
  168 iconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp)
  169 {
  170         struct iconv_cspair *csp;
  171 
  172         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  173                 if (strcasecmp(csp->cp_to, to) == 0 &&
  174                     strcasecmp(csp->cp_from, from) == 0) {
  175                         if (cspp)
  176                                 *cspp = csp;
  177                         return 0;
  178                 }
  179         }
  180         return ENOENT;
  181 }
  182 
  183 static int
  184 iconv_register_cspair(const char *to, const char *from,
  185         struct iconv_converter_class *dcp, void *data,
  186         struct iconv_cspair **cspp)
  187 {
  188         struct iconv_cspair *csp;
  189         char *cp;
  190         int csize, ucsto, ucsfrom;
  191 
  192         if (iconv_lookupcs(to, from, NULL) == 0)
  193                 return EEXIST;
  194         csize = sizeof(*csp);
  195         ucsto = strcmp(to, iconv_unicode_string) == 0;
  196         if (!ucsto)
  197                 csize += strlen(to) + 1;
  198         ucsfrom = strcmp(from, iconv_unicode_string) == 0;
  199         if (!ucsfrom)
  200                 csize += strlen(from) + 1;
  201         csp = malloc(csize, M_ICONV, M_WAITOK);
  202         bzero(csp, csize);
  203         csp->cp_id = iconv_csid++;
  204         csp->cp_dcp = dcp;
  205         cp = (char*)(csp + 1);
  206         if (!ucsto) {
  207                 strcpy(cp, to);
  208                 csp->cp_to = cp;
  209                 cp += strlen(cp) + 1;
  210         } else
  211                 csp->cp_to = iconv_unicode_string;
  212         if (!ucsfrom) {
  213                 strcpy(cp, from);
  214                 csp->cp_from = cp;
  215         } else
  216                 csp->cp_from = iconv_unicode_string;
  217         csp->cp_data = data;
  218 
  219         TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link);
  220         *cspp = csp;
  221         return 0;
  222 }
  223 
  224 static void
  225 iconv_unregister_cspair(struct iconv_cspair *csp)
  226 {
  227         TAILQ_REMOVE(&iconv_cslist, csp, cp_link);
  228         if (csp->cp_data)
  229                 free(csp->cp_data, M_ICONVDATA);
  230         free(csp, M_ICONV);
  231 }
  232 
  233 /*
  234  * Lookup and create an instance of converter.
  235  * Currently this layer didn't have associated 'instance' structure
  236  * to avoid unnesessary memory allocation.
  237  */
  238 int
  239 iconv_open(const char *to, const char *from, void **handle)
  240 {
  241         struct iconv_cspair *csp, *cspfrom, *cspto;
  242         struct iconv_converter_class *dcp;
  243         const char *cnvname;
  244         int error;
  245 
  246         /*
  247          * First, lookup fully qualified cspairs
  248          */
  249         error = iconv_lookupcs(to, from, &csp);
  250         if (error == 0)
  251                 return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle);
  252 
  253         /*
  254          * Well, nothing found. Now try to construct a composite conversion
  255          * ToDo: add a 'capability' field to converter
  256          */
  257         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  258                 cnvname = ICONV_CONVERTER_NAME(dcp);
  259                 if (cnvname == NULL)
  260                         continue;
  261                 error = iconv_lookupcs(cnvname, from, &cspfrom);
  262                 if (error)
  263                         continue;
  264                 error = iconv_lookupcs(to, cnvname, &cspto);
  265                 if (error)
  266                         continue;
  267                 /*
  268                  * Fine, we're found a pair which can be combined together
  269                  */
  270                 return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle);
  271         }
  272         return ENOENT;
  273 }
  274 
  275 int
  276 iconv_close(void *handle)
  277 {
  278         return ICONV_CONVERTER_CLOSE(handle);
  279 }
  280 
  281 int
  282 iconv_conv(void *handle, const char **inbuf,
  283         size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
  284 {
  285         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0);
  286 }
  287 
  288 int
  289 iconv_conv_case(void *handle, const char **inbuf,
  290         size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
  291 {
  292         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype);
  293 }
  294 
  295 int
  296 iconv_convchr(void *handle, const char **inbuf,
  297         size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
  298 {
  299         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0);
  300 }
  301 
  302 int
  303 iconv_convchr_case(void *handle, const char **inbuf,
  304         size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
  305 {
  306         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype);
  307 }
  308 
  309 int
  310 towlower(int c, void *handle)
  311 {
  312         return ICONV_CONVERTER_TOLOWER(handle, c);
  313 }
  314 
  315 int
  316 towupper(int c, void *handle)
  317 {
  318         return ICONV_CONVERTER_TOUPPER(handle, c);
  319 }
  320 
  321 /*
  322  * Give a list of loaded converters. Each name terminated with 0.
  323  * An empty string terminates the list.
  324  */
  325 static int
  326 iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
  327 {
  328         struct iconv_converter_class *dcp;
  329         const char *name;
  330         char spc;
  331         int error;
  332 
  333         error = 0;
  334         sx_slock(&iconv_lock);
  335         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  336                 name = ICONV_CONVERTER_NAME(dcp);
  337                 if (name == NULL)
  338                         continue;
  339                 error = SYSCTL_OUT(req, name, strlen(name) + 1);
  340                 if (error)
  341                         break;
  342         }
  343         sx_sunlock(&iconv_lock);
  344         if (error)
  345                 return error;
  346         spc = 0;
  347         error = SYSCTL_OUT(req, &spc, sizeof(spc));
  348         return error;
  349 }
  350 
  351 SYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  352             NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters");
  353 
  354 /*
  355  * List all available charset pairs.
  356  */
  357 static int
  358 iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
  359 {
  360         struct iconv_cspair *csp;
  361         struct iconv_cspair_info csi;
  362         int error;
  363 
  364         error = 0;
  365         bzero(&csi, sizeof(csi));
  366         csi.cs_version = ICONV_CSPAIR_INFO_VER;
  367         sx_slock(&iconv_lock);
  368         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  369                 csi.cs_id = csp->cp_id;
  370                 csi.cs_refcount = csp->cp_refcount;
  371                 csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0;
  372                 strcpy(csi.cs_to, csp->cp_to);
  373                 strcpy(csi.cs_from, csp->cp_from);
  374                 error = SYSCTL_OUT(req, &csi, sizeof(csi));
  375                 if (error)
  376                         break;
  377         }
  378         sx_sunlock(&iconv_lock);
  379         return error;
  380 }
  381 
  382 SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  383             NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs");
  384 
  385 int
  386 iconv_add(const char *converter, const char *to, const char *from)
  387 {
  388         struct iconv_converter_class *dcp;
  389         struct iconv_cspair *csp;
  390 
  391         if (iconv_lookupconv(converter, &dcp) != 0)
  392                 return EINVAL;
  393 
  394         return iconv_register_cspair(to, from, dcp, NULL, &csp);
  395 }
  396 
  397 /*
  398  * Add new charset pair
  399  */
  400 static int
  401 iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
  402 {
  403         struct iconv_converter_class *dcp;
  404         struct iconv_cspair *csp;
  405         struct iconv_add_in din;
  406         struct iconv_add_out dout;
  407         int error;
  408 
  409         error = SYSCTL_IN(req, &din, sizeof(din));
  410         if (error)
  411                 return error;
  412         if (din.ia_version != ICONV_ADD_VER)
  413                 return EINVAL;
  414         if (din.ia_datalen > ICONV_CSMAXDATALEN)
  415                 return EINVAL;
  416         if (strnlen(din.ia_from, sizeof(din.ia_from)) >= ICONV_CSNMAXLEN)
  417                 return EINVAL;
  418         if (strnlen(din.ia_to, sizeof(din.ia_to)) >= ICONV_CSNMAXLEN)
  419                 return EINVAL;
  420         if (strnlen(din.ia_converter, sizeof(din.ia_converter)) >= ICONV_CNVNMAXLEN)
  421                 return EINVAL;
  422         if (iconv_lookupconv(din.ia_converter, &dcp) != 0)
  423                 return EINVAL;
  424         sx_xlock(&iconv_lock);
  425         error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp);
  426         if (error) {
  427                 sx_xunlock(&iconv_lock);
  428                 return error;
  429         }
  430         if (din.ia_datalen) {
  431                 csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK);
  432                 error = copyin(din.ia_data, csp->cp_data, din.ia_datalen);
  433                 if (error)
  434                         goto bad;
  435         }
  436         dout.ia_csid = csp->cp_id;
  437         error = SYSCTL_OUT(req, &dout, sizeof(dout));
  438         if (error)
  439                 goto bad;
  440         sx_xunlock(&iconv_lock);
  441         ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
  442         return 0;
  443 bad:
  444         iconv_unregister_cspair(csp);
  445         sx_xunlock(&iconv_lock);
  446         return error;
  447 }
  448 
  449 SYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE,
  450             NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair");
  451 
  452 /*
  453  * Default stubs for converters
  454  */
  455 int
  456 iconv_converter_initstub(struct iconv_converter_class *dp)
  457 {
  458         return 0;
  459 }
  460 
  461 int
  462 iconv_converter_donestub(struct iconv_converter_class *dp)
  463 {
  464         return 0;
  465 }
  466 
  467 int
  468 iconv_converter_tolowerstub(int c, void *handle)
  469 {
  470         return (c);
  471 }
  472 
  473 int
  474 iconv_converter_handler(module_t mod, int type, void *data)
  475 {
  476         struct iconv_converter_class *dcp = data;
  477         int error;
  478 
  479         switch (type) {
  480             case MOD_LOAD:
  481                 sx_xlock(&iconv_lock);
  482                 error = iconv_register_converter(dcp);
  483                 if (error) {
  484                         sx_xunlock(&iconv_lock);
  485                         break;
  486                 }
  487                 error = ICONV_CONVERTER_INIT(dcp);
  488                 if (error)
  489                         iconv_unregister_converter(dcp);
  490                 sx_xunlock(&iconv_lock);
  491                 break;
  492             case MOD_UNLOAD:
  493                 sx_xlock(&iconv_lock);
  494                 ICONV_CONVERTER_DONE(dcp);
  495                 error = iconv_unregister_converter(dcp);
  496                 sx_xunlock(&iconv_lock);
  497                 break;
  498             default:
  499                 error = EINVAL;
  500         }
  501         return error;
  502 }
  503 
  504 /*
  505  * Common used functions (don't use with unicode)
  506  */
  507 char *
  508 iconv_convstr(void *handle, char *dst, const char *src)
  509 {
  510         char *p = dst;
  511         size_t inlen, outlen;
  512         int error;
  513 
  514         if (handle == NULL) {
  515                 strcpy(dst, src);
  516                 return dst;
  517         }
  518         inlen = outlen = strlen(src);
  519         error = iconv_conv(handle, NULL, NULL, &p, &outlen);
  520         if (error)
  521                 return NULL;
  522         error = iconv_conv(handle, &src, &inlen, &p, &outlen);
  523         if (error)
  524                 return NULL;
  525         *p = 0;
  526         return dst;
  527 }
  528 
  529 void *
  530 iconv_convmem(void *handle, void *dst, const void *src, int size)
  531 {
  532         const char *s = src;
  533         char *d = dst;
  534         size_t inlen, outlen;
  535         int error;
  536 
  537         if (size == 0)
  538                 return dst;
  539         if (handle == NULL) {
  540                 memcpy(dst, src, size);
  541                 return dst;
  542         }
  543         inlen = outlen = size;
  544         error = iconv_conv(handle, NULL, NULL, &d, &outlen);
  545         if (error)
  546                 return NULL;
  547         error = iconv_conv(handle, &s, &inlen, &d, &outlen);
  548         if (error)
  549                 return NULL;
  550         return dst;
  551 }
  552 
  553 int
  554 iconv_lookupcp(char **cpp, const char *s)
  555 {
  556         if (cpp == NULL) {
  557                 ICDEBUG("warning a NULL list passed\n", "");
  558                 return ENOENT;
  559         }
  560         for (; *cpp; cpp++)
  561                 if (strcmp(*cpp, s) == 0)
  562                         return 0;
  563         return ENOENT;
  564 }
  565 
  566 /*
  567  * Return if fsname is in use of not
  568  */
  569 int
  570 iconv_vfs_refcount(const char *fsname)
  571 {
  572         struct vfsconf *vfsp;
  573 
  574         vfsp = vfs_byname(fsname);
  575         if (vfsp != NULL && vfsp->vfc_refcount > 0)
  576                 return (EBUSY);
  577         return (0);
  578 }

Cache object: 79fea8842b5797bc8d73549b99165096


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.