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

Cache object: d1ee1fc8ea0597fb26c7c4eae9f8396b


[ 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.