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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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/9.0/sys/libkern/iconv.c 206361 2010-04-07 16:50:38Z joel $");
   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 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         while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL) {
   88                 if (csp->cp_refcount)
   89                         return EBUSY;
   90         }
   91 
   92         while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL)
   93                 iconv_unregister_cspair(csp);
   94         sx_xunlock(&iconv_lock);
   95         sx_destroy(&iconv_lock);
   96         return 0;
   97 }
   98 
   99 static int
  100 iconv_mod_handler(module_t mod, int type, void *data)
  101 {
  102         int error;
  103 
  104         switch (type) {
  105             case MOD_LOAD:
  106                 error = 0;
  107                 sx_init(&iconv_lock, "iconv");
  108                 break;
  109             case MOD_UNLOAD:
  110                 error = iconv_mod_unload();
  111                 break;
  112             default:
  113                 error = EINVAL;
  114         }
  115         return error;
  116 }
  117 
  118 static moduledata_t iconv_mod = {
  119         "iconv", iconv_mod_handler, NULL
  120 };
  121 
  122 DECLARE_MODULE(iconv, iconv_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  123 
  124 static int
  125 iconv_register_converter(struct iconv_converter_class *dcp)
  126 {
  127         kobj_class_compile((struct kobj_class*)dcp);
  128         dcp->refs++;
  129         TAILQ_INSERT_TAIL(&iconv_converters, dcp, cc_link);
  130         return 0;
  131 }
  132 
  133 static int
  134 iconv_unregister_converter(struct iconv_converter_class *dcp)
  135 {
  136         if (dcp->refs > 1) {
  137                 ICDEBUG("converter have %d referenses left\n", dcp->refs);
  138                 return EBUSY;
  139         }
  140         TAILQ_REMOVE(&iconv_converters, dcp, cc_link);
  141         kobj_class_free((struct kobj_class*)dcp);
  142         return 0;
  143 }
  144 
  145 static int
  146 iconv_lookupconv(const char *name, struct iconv_converter_class **dcpp)
  147 {
  148         struct iconv_converter_class *dcp;
  149 
  150         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  151                 if (name == NULL)
  152                         continue;
  153                 if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) {
  154                         if (dcpp)
  155                                 *dcpp = dcp;
  156                         return 0;
  157                 }
  158         }
  159         return ENOENT;
  160 }
  161 
  162 static int
  163 iconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp)
  164 {
  165         struct iconv_cspair *csp;
  166 
  167         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  168                 if (strcmp(csp->cp_to, to) == 0 &&
  169                     strcmp(csp->cp_from, from) == 0) {
  170                         if (cspp)
  171                                 *cspp = csp;
  172                         return 0;
  173                 }
  174         }
  175         return ENOENT;
  176 }
  177 
  178 static int
  179 iconv_register_cspair(const char *to, const char *from,
  180         struct iconv_converter_class *dcp, void *data,
  181         struct iconv_cspair **cspp)
  182 {
  183         struct iconv_cspair *csp;
  184         char *cp;
  185         int csize, ucsto, ucsfrom;
  186 
  187         if (iconv_lookupcs(to, from, NULL) == 0)
  188                 return EEXIST;
  189         csize = sizeof(*csp);
  190         ucsto = strcmp(to, iconv_unicode_string) == 0;
  191         if (!ucsto)
  192                 csize += strlen(to) + 1;
  193         ucsfrom = strcmp(from, iconv_unicode_string) == 0;
  194         if (!ucsfrom)
  195                 csize += strlen(from) + 1;
  196         csp = malloc(csize, M_ICONV, M_WAITOK);
  197         bzero(csp, csize);
  198         csp->cp_id = iconv_csid++;
  199         csp->cp_dcp = dcp;
  200         cp = (char*)(csp + 1);
  201         if (!ucsto) {
  202                 strcpy(cp, to);
  203                 csp->cp_to = cp;
  204                 cp += strlen(cp) + 1;
  205         } else
  206                 csp->cp_to = iconv_unicode_string;
  207         if (!ucsfrom) {
  208                 strcpy(cp, from);
  209                 csp->cp_from = cp;
  210         } else
  211                 csp->cp_from = iconv_unicode_string;
  212         csp->cp_data = data;
  213 
  214         TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link);
  215         *cspp = csp;
  216         return 0;
  217 }
  218 
  219 static void
  220 iconv_unregister_cspair(struct iconv_cspair *csp)
  221 {
  222         TAILQ_REMOVE(&iconv_cslist, csp, cp_link);
  223         if (csp->cp_data)
  224                 free(csp->cp_data, M_ICONVDATA);
  225         free(csp, M_ICONV);
  226 }
  227 
  228 /*
  229  * Lookup and create an instance of converter.
  230  * Currently this layer didn't have associated 'instance' structure
  231  * to avoid unnesessary memory allocation.
  232  */
  233 int
  234 iconv_open(const char *to, const char *from, void **handle)
  235 {
  236         struct iconv_cspair *csp, *cspfrom, *cspto;
  237         struct iconv_converter_class *dcp;
  238         const char *cnvname;
  239         int error;
  240 
  241         /*
  242          * First, lookup fully qualified cspairs
  243          */
  244         error = iconv_lookupcs(to, from, &csp);
  245         if (error == 0)
  246                 return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle);
  247 
  248         /*
  249          * Well, nothing found. Now try to construct a composite conversion
  250          * ToDo: add a 'capability' field to converter
  251          */
  252         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  253                 cnvname = ICONV_CONVERTER_NAME(dcp);
  254                 if (cnvname == NULL)
  255                         continue;
  256                 error = iconv_lookupcs(cnvname, from, &cspfrom);
  257                 if (error)
  258                         continue;
  259                 error = iconv_lookupcs(to, cnvname, &cspto);
  260                 if (error)
  261                         continue;
  262                 /*
  263                  * Fine, we're found a pair which can be combined together
  264                  */
  265                 return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle);
  266         }
  267         return ENOENT;
  268 }
  269 
  270 int
  271 iconv_close(void *handle)
  272 {
  273         return ICONV_CONVERTER_CLOSE(handle);
  274 }
  275 
  276 int
  277 iconv_conv(void *handle, const char **inbuf,
  278         size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
  279 {
  280         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0);
  281 }
  282 
  283 int
  284 iconv_conv_case(void *handle, const char **inbuf,
  285         size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
  286 {
  287         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype);
  288 }
  289 
  290 int
  291 iconv_convchr(void *handle, const char **inbuf,
  292         size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
  293 {
  294         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0);
  295 }
  296 
  297 int
  298 iconv_convchr_case(void *handle, const char **inbuf,
  299         size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
  300 {
  301         return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype);
  302 }
  303 
  304 int
  305 towlower(int c, void *handle)
  306 {
  307         return ICONV_CONVERTER_TOLOWER(handle, c);
  308 }
  309 
  310 int
  311 towupper(int c, void *handle)
  312 {
  313         return ICONV_CONVERTER_TOUPPER(handle, c);
  314 }
  315 
  316 /*
  317  * Give a list of loaded converters. Each name terminated with 0.
  318  * An empty string terminates the list.
  319  */
  320 static int
  321 iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS)
  322 {
  323         struct iconv_converter_class *dcp;
  324         const char *name;
  325         char spc;
  326         int error;
  327 
  328         error = 0;
  329         sx_slock(&iconv_lock);
  330         TAILQ_FOREACH(dcp, &iconv_converters, cc_link) {
  331                 name = ICONV_CONVERTER_NAME(dcp);
  332                 if (name == NULL)
  333                         continue;
  334                 error = SYSCTL_OUT(req, name, strlen(name) + 1);
  335                 if (error)
  336                         break;
  337         }
  338         sx_sunlock(&iconv_lock);
  339         if (error)
  340                 return error;
  341         spc = 0;
  342         error = SYSCTL_OUT(req, &spc, sizeof(spc));
  343         return error;
  344 }
  345 
  346 SYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  347             NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters");
  348 
  349 /*
  350  * List all available charset pairs.
  351  */
  352 static int
  353 iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS)
  354 {
  355         struct iconv_cspair *csp;
  356         struct iconv_cspair_info csi;
  357         int error;
  358 
  359         error = 0;
  360         bzero(&csi, sizeof(csi));
  361         csi.cs_version = ICONV_CSPAIR_INFO_VER;
  362         sx_slock(&iconv_lock);
  363         TAILQ_FOREACH(csp, &iconv_cslist, cp_link) {
  364                 csi.cs_id = csp->cp_id;
  365                 csi.cs_refcount = csp->cp_refcount;
  366                 csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0;
  367                 strcpy(csi.cs_to, csp->cp_to);
  368                 strcpy(csi.cs_from, csp->cp_from);
  369                 error = SYSCTL_OUT(req, &csi, sizeof(csi));
  370                 if (error)
  371                         break;
  372         }
  373         sx_sunlock(&iconv_lock);
  374         return error;
  375 }
  376 
  377 SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE,
  378             NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs");
  379 
  380 /*
  381  * Add new charset pair
  382  */
  383 static int
  384 iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
  385 {
  386         struct iconv_converter_class *dcp;
  387         struct iconv_cspair *csp;
  388         struct iconv_add_in din;
  389         struct iconv_add_out dout;
  390         int error;
  391 
  392         error = SYSCTL_IN(req, &din, sizeof(din));
  393         if (error)
  394                 return error;
  395         if (din.ia_version != ICONV_ADD_VER)
  396                 return EINVAL;
  397         if (din.ia_datalen > ICONV_CSMAXDATALEN)
  398                 return EINVAL;
  399         if (strlen(din.ia_from) >= ICONV_CSNMAXLEN)
  400                 return EINVAL;
  401         if (strlen(din.ia_to) >= ICONV_CSNMAXLEN)
  402                 return EINVAL;
  403         if (strlen(din.ia_converter) >= ICONV_CNVNMAXLEN)
  404                 return EINVAL;
  405         if (iconv_lookupconv(din.ia_converter, &dcp) != 0)
  406                 return EINVAL;
  407         sx_xlock(&iconv_lock);
  408         error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp);
  409         if (error) {
  410                 sx_xunlock(&iconv_lock);
  411                 return error;
  412         }
  413         if (din.ia_datalen) {
  414                 csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK);
  415                 error = copyin(din.ia_data, csp->cp_data, din.ia_datalen);
  416                 if (error)
  417                         goto bad;
  418         }
  419         dout.ia_csid = csp->cp_id;
  420         error = SYSCTL_OUT(req, &dout, sizeof(dout));
  421         if (error)
  422                 goto bad;
  423         sx_xunlock(&iconv_lock);
  424         ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
  425         return 0;
  426 bad:
  427         iconv_unregister_cspair(csp);
  428         sx_xunlock(&iconv_lock);
  429         return error;
  430 }
  431 
  432 SYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE,
  433             NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair");
  434 
  435 /*
  436  * Default stubs for converters
  437  */
  438 int
  439 iconv_converter_initstub(struct iconv_converter_class *dp)
  440 {
  441         return 0;
  442 }
  443 
  444 int
  445 iconv_converter_donestub(struct iconv_converter_class *dp)
  446 {
  447         return 0;
  448 }
  449 
  450 int
  451 iconv_converter_tolowerstub(int c, void *handle)
  452 {
  453         return (c);
  454 }
  455 
  456 int
  457 iconv_converter_handler(module_t mod, int type, void *data)
  458 {
  459         struct iconv_converter_class *dcp = data;
  460         int error;
  461 
  462         switch (type) {
  463             case MOD_LOAD:
  464                 sx_xlock(&iconv_lock);
  465                 error = iconv_register_converter(dcp);
  466                 if (error) {
  467                         sx_xunlock(&iconv_lock);
  468                         break;
  469                 }
  470                 error = ICONV_CONVERTER_INIT(dcp);
  471                 if (error)
  472                         iconv_unregister_converter(dcp);
  473                 sx_xunlock(&iconv_lock);
  474                 break;
  475             case MOD_UNLOAD:
  476                 sx_xlock(&iconv_lock);
  477                 ICONV_CONVERTER_DONE(dcp);
  478                 error = iconv_unregister_converter(dcp);
  479                 sx_xunlock(&iconv_lock);
  480                 break;
  481             default:
  482                 error = EINVAL;
  483         }
  484         return error;
  485 }
  486 
  487 /*
  488  * Common used functions (don't use with unicode)
  489  */
  490 char *
  491 iconv_convstr(void *handle, char *dst, const char *src)
  492 {
  493         char *p = dst;
  494         size_t inlen, outlen;
  495         int error;
  496 
  497         if (handle == NULL) {
  498                 strcpy(dst, src);
  499                 return dst;
  500         }
  501         inlen = outlen = strlen(src);
  502         error = iconv_conv(handle, NULL, NULL, &p, &outlen);
  503         if (error)
  504                 return NULL;
  505         error = iconv_conv(handle, &src, &inlen, &p, &outlen);
  506         if (error)
  507                 return NULL;
  508         *p = 0;
  509         return dst;
  510 }
  511 
  512 void *
  513 iconv_convmem(void *handle, void *dst, const void *src, int size)
  514 {
  515         const char *s = src;
  516         char *d = dst;
  517         size_t inlen, outlen;
  518         int error;
  519 
  520         if (size == 0)
  521                 return dst;
  522         if (handle == NULL) {
  523                 memcpy(dst, src, size);
  524                 return dst;
  525         }
  526         inlen = outlen = size;
  527         error = iconv_conv(handle, NULL, NULL, &d, &outlen);
  528         if (error)
  529                 return NULL;
  530         error = iconv_conv(handle, &s, &inlen, &d, &outlen);
  531         if (error)
  532                 return NULL;
  533         return dst;
  534 }
  535 
  536 int
  537 iconv_lookupcp(char **cpp, const char *s)
  538 {
  539         if (cpp == NULL) {
  540                 ICDEBUG("warning a NULL list passed\n", ""); /* XXX ISO variadic                                                                macros cannot
  541                                                                 leave out the
  542                                                                 variadic args */
  543                 return ENOENT;
  544         }
  545         for (; *cpp; cpp++)
  546                 if (strcmp(*cpp, s) == 0)
  547                         return 0;
  548         return ENOENT;
  549 }
  550 
  551 /*
  552  * Return if fsname is in use of not
  553  */
  554 int
  555 iconv_vfs_refcount(const char *fsname)
  556 {
  557         struct vfsconf *vfsp;
  558 
  559         vfsp = vfs_byname(fsname);
  560         if (vfsp != NULL && vfsp->vfc_refcount > 0)
  561                 return (EBUSY);
  562         return (0);
  563 }

Cache object: ab56c8a334050288146f4133e7fa4064


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