17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57257d1b4Sraf * Common Development and Distribution License (the "License"). 67257d1b4Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217257d1b4Sraf 227c478bd9Sstevel@tonic-gate /* 23b8d94837SIenup Sung * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277257d1b4Sraf #include "lint.h" 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/stat.h> 307c478bd9Sstevel@tonic-gate #include <sys/mman.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <dlfcn.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <unistd.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <alloca.h> 407c478bd9Sstevel@tonic-gate #include "iconv.h" 417c478bd9Sstevel@tonic-gate #include "iconvP.h" 427c478bd9Sstevel@tonic-gate #include "../i18n/_loc_path.h" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate static iconv_p iconv_open_all(const char *, const char *, char *); 457c478bd9Sstevel@tonic-gate static iconv_p iconv_open_private(const char *, const char *); 467c478bd9Sstevel@tonic-gate static iconv_p iconv_search_alias(const char *, const char *, char *); 47b8d94837SIenup Sung static size_t passthru_icv_iconv(iconv_t, const char **, size_t *, char **, 48b8d94837SIenup Sung size_t *); 49b8d94837SIenup Sung static void passthru_icv_close(iconv_t); 50b8d94837SIenup Sung 51b8d94837SIenup Sung #define PASSTHRU_MAGIC_NUMBER (0x53756e) 52b8d94837SIenup Sung 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 55b8d94837SIenup Sung * These functions are mainly implemented by using a shared object and 56b8d94837SIenup Sung * the dlopen() functions. The actual conversion algorithm for a particular 57b8d94837SIenup Sung * conversion is implemented via a shared object as a loadable conversion 58b8d94837SIenup Sung * module which is linked dynamically at run time. 59b8d94837SIenup Sung * 60b8d94837SIenup Sung * The loadable conversion module resides as either: 61b8d94837SIenup Sung * 62b8d94837SIenup Sung * /usr/lib/iconv/geniconvtbl.so 63b8d94837SIenup Sung * 64b8d94837SIenup Sung * if the conversion is supported through a geniconvtbl code conversion 65b8d94837SIenup Sung * binary table or as a module that directly specifies the conversion at: 66b8d94837SIenup Sung * 677c478bd9Sstevel@tonic-gate * /usr/lib/iconv/fromcode%tocode.so 68b8d94837SIenup Sung * 697c478bd9Sstevel@tonic-gate * where fromcode is the source encoding and tocode is the target encoding. 70b8d94837SIenup Sung * The modules have 3 entries: _icv_open(), _icv_iconv(), and _icv_close(). 71b8d94837SIenup Sung * 72b8d94837SIenup Sung * If there is no code conversion supported and if the fromcode and the tocode 73b8d94837SIenup Sung * are specifying the same codeset, then, the byte-by-byte, pass-through code 74b8d94837SIenup Sung * conversion that is embedded in the libc is used instead. 75b8d94837SIenup Sung * 76b8d94837SIenup Sung * The following are the related PSARC cases: 77b8d94837SIenup Sung * 78b8d94837SIenup Sung * PSARC/1993/153 iconv/iconv_open/iconv_close 79b8d94837SIenup Sung * PSARC/1999/292 Addition of geniconvtbl(1) 80b8d94837SIenup Sung * PSARC/2001/072 GNU gettext support 81b8d94837SIenup Sung * PSARC/2009/561 Pass-through iconv code conversion 82b8d94837SIenup Sung * 83b8d94837SIenup Sung * The PSARC/2001/072 includes the /usr/lib/iconv/alias interface. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate iconv_t 877257d1b4Sraf iconv_open(const char *tocode, const char *fromcode) 887c478bd9Sstevel@tonic-gate { 897c478bd9Sstevel@tonic-gate iconv_t cd; 907c478bd9Sstevel@tonic-gate char *ipath; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate if ((cd = malloc(sizeof (struct _iconv_info))) == NULL) 937c478bd9Sstevel@tonic-gate return ((iconv_t)-1); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Memory for ipath is allocated/released in this function. 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate ipath = malloc(MAXPATHLEN); 997c478bd9Sstevel@tonic-gate if (ipath == NULL) { 1007c478bd9Sstevel@tonic-gate free(cd); 1017c478bd9Sstevel@tonic-gate return ((iconv_t)-1); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate cd->_conv = iconv_open_all(tocode, fromcode, ipath); 1057c478bd9Sstevel@tonic-gate if (cd->_conv != (iconv_p)-1) { 1067c478bd9Sstevel@tonic-gate /* found a valid module for this conversion */ 1077c478bd9Sstevel@tonic-gate free(ipath); 1087c478bd9Sstevel@tonic-gate return (cd); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * Now, try using the encoding name aliasing table 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate cd->_conv = iconv_search_alias(tocode, fromcode, ipath); 1157c478bd9Sstevel@tonic-gate free(ipath); 1167c478bd9Sstevel@tonic-gate if (cd->_conv == (iconv_p)-1) { 117b8d94837SIenup Sung /* 118b8d94837SIenup Sung * As the last resort, check if the tocode and the fromcode 119b8d94837SIenup Sung * are referring to the same codeset name or not. If so, 120b8d94837SIenup Sung * assign the embedded pass-through code conversion. 121b8d94837SIenup Sung */ 122b8d94837SIenup Sung if (strcasecmp(tocode, fromcode) != 0) { 123b8d94837SIenup Sung /* 124b8d94837SIenup Sung * No valid conversion available. Do failure retrun 125b8d94837SIenup Sung * with the errno set by iconv_search_alias(). 126b8d94837SIenup Sung */ 1277c478bd9Sstevel@tonic-gate free(cd); 1287c478bd9Sstevel@tonic-gate return ((iconv_t)-1); 1297c478bd9Sstevel@tonic-gate } 130b8d94837SIenup Sung 131b8d94837SIenup Sung /* 132b8d94837SIenup Sung * For a pass-through byte-by-byte code conversion, allocate 133b8d94837SIenup Sung * an internal conversion descriptor and initialize the data 134b8d94837SIenup Sung * fields appropriately and we are done. 135b8d94837SIenup Sung */ 136b8d94837SIenup Sung cd->_conv = malloc(sizeof (struct _iconv_fields)); 137b8d94837SIenup Sung if (cd->_conv == NULL) { 138b8d94837SIenup Sung free(cd); 139b8d94837SIenup Sung return ((iconv_t)-1); 140b8d94837SIenup Sung } 141b8d94837SIenup Sung 142b8d94837SIenup Sung cd->_conv->_icv_handle = NULL; 143b8d94837SIenup Sung cd->_conv->_icv_iconv = passthru_icv_iconv; 144b8d94837SIenup Sung cd->_conv->_icv_close = passthru_icv_close; 145b8d94837SIenup Sung cd->_conv->_icv_state = (void *)PASSTHRU_MAGIC_NUMBER; 146b8d94837SIenup Sung } 147b8d94837SIenup Sung 1487c478bd9Sstevel@tonic-gate /* found a valid module for this conversion */ 1497c478bd9Sstevel@tonic-gate return (cd); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate static size_t 1537c478bd9Sstevel@tonic-gate search_alias(char **paddr, size_t size, const char *variant) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate char *addr = *paddr; 1567c478bd9Sstevel@tonic-gate char *p, *sp, *q; 1577c478bd9Sstevel@tonic-gate size_t var_len, can_len; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate var_len = strlen(variant); 1607c478bd9Sstevel@tonic-gate p = addr; 1617c478bd9Sstevel@tonic-gate q = addr + size; 1627c478bd9Sstevel@tonic-gate while (q > p) { 1637c478bd9Sstevel@tonic-gate if (*p == '#') { 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Line beginning with '#' is a comment 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate p++; 1687c478bd9Sstevel@tonic-gate while ((q > p) && (*p++ != '\n')) 1697c478bd9Sstevel@tonic-gate ; 1707c478bd9Sstevel@tonic-gate continue; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate /* skip leading spaces */ 1737c478bd9Sstevel@tonic-gate while ((q > p) && 1747c478bd9Sstevel@tonic-gate ((*p == ' ') || (*p == '\t'))) 1757c478bd9Sstevel@tonic-gate p++; 1767c478bd9Sstevel@tonic-gate if (q <= p) 1777c478bd9Sstevel@tonic-gate break; 1787c478bd9Sstevel@tonic-gate sp = p; 1797c478bd9Sstevel@tonic-gate while ((q > p) && (*p != ' ') && 1807c478bd9Sstevel@tonic-gate (*p != '\t') && (*p != '\n')) 1817c478bd9Sstevel@tonic-gate p++; 1827c478bd9Sstevel@tonic-gate if (q <= p) { 1837c478bd9Sstevel@tonic-gate /* invalid entry */ 1847c478bd9Sstevel@tonic-gate break; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate if (*p == '\n') { 1877c478bd9Sstevel@tonic-gate /* invalid entry */ 1887c478bd9Sstevel@tonic-gate p++; 1897c478bd9Sstevel@tonic-gate continue; 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate if (((p - sp) != var_len) || 1937c478bd9Sstevel@tonic-gate ((strncmp(sp, variant, var_len) != 0) && 1947c478bd9Sstevel@tonic-gate (strncasecmp(sp, variant, var_len) != 0))) { 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * didn't match 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* skip remaining chars in this line */ 2007c478bd9Sstevel@tonic-gate p++; 2017c478bd9Sstevel@tonic-gate while ((q > p) && (*p++ != '\n')) 2027c478bd9Sstevel@tonic-gate ; 2037c478bd9Sstevel@tonic-gate continue; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* matching entry found */ 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* skip spaces */ 2097c478bd9Sstevel@tonic-gate while ((q > p) && 2107c478bd9Sstevel@tonic-gate ((*p == ' ') || (*p == '\t'))) 2117c478bd9Sstevel@tonic-gate p++; 2127c478bd9Sstevel@tonic-gate if (q <= p) 2137c478bd9Sstevel@tonic-gate break; 2147c478bd9Sstevel@tonic-gate sp = p; 2157c478bd9Sstevel@tonic-gate while ((q > p) && (*p != ' ') && 2167c478bd9Sstevel@tonic-gate (*p != '\t') && (*p != '\n')) 2177c478bd9Sstevel@tonic-gate p++; 2187c478bd9Sstevel@tonic-gate can_len = p - sp; 2197c478bd9Sstevel@tonic-gate if (can_len == 0) { 2207c478bd9Sstevel@tonic-gate while ((q > p) && (*p++ != '\n')) 2217c478bd9Sstevel@tonic-gate ; 2227c478bd9Sstevel@tonic-gate continue; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate *paddr = sp; 2257c478bd9Sstevel@tonic-gate return (can_len); 2267c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate return (0); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate static iconv_p 2327c478bd9Sstevel@tonic-gate iconv_open_all(const char *to, const char *from, char *ipath) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate iconv_p cv; 2357c478bd9Sstevel@tonic-gate int len; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * First, try using the geniconvtbl conversion, which is 2397c478bd9Sstevel@tonic-gate * performed by /usr/lib/iconv/geniconvtbl.so with 2407c478bd9Sstevel@tonic-gate * the conversion table file: 2417c478bd9Sstevel@tonic-gate * /usr/lib/iconv/geniconvtbl/binarytables/fromcode%tocode.bt 2427c478bd9Sstevel@tonic-gate * 2437c478bd9Sstevel@tonic-gate * If the geniconvtbl conversion cannot be done, 2447c478bd9Sstevel@tonic-gate * try the conversion by the individual shared object. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate len = snprintf(ipath, MAXPATHLEN, _GENICONVTBL_PATH, from, to); 2487c478bd9Sstevel@tonic-gate if ((len <= MAXPATHLEN) && (access(ipath, R_OK) == 0)) { 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * from%to.bt exists in the table dir 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate cv = iconv_open_private(_GENICONVTBL_INT_PATH, ipath); 2537c478bd9Sstevel@tonic-gate if (cv != (iconv_p)-1) { 2547c478bd9Sstevel@tonic-gate /* found a valid module for this conversion */ 2557c478bd9Sstevel@tonic-gate return (cv); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* Next, try /usr/lib/iconv/from%to.so */ 2607c478bd9Sstevel@tonic-gate len = snprintf(ipath, MAXPATHLEN, _ICONV_PATH, from, to); 2617c478bd9Sstevel@tonic-gate if ((len <= MAXPATHLEN) && (access(ipath, R_OK) == 0)) { 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * /usr/lib/iconv/from%to.so exists 2647c478bd9Sstevel@tonic-gate * errno will be set by iconv_open_private on error 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate return (iconv_open_private(ipath, NULL)); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate /* no valid module for this conversion found */ 2697c478bd9Sstevel@tonic-gate errno = EINVAL; 2707c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate static iconv_p 2747c478bd9Sstevel@tonic-gate iconv_search_alias(const char *tocode, const char *fromcode, char *ipath) 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate char *p; 2777c478bd9Sstevel@tonic-gate char *to_canonical, *from_canonical; 2787c478bd9Sstevel@tonic-gate size_t tolen, fromlen; 2797c478bd9Sstevel@tonic-gate iconv_p cv; 2807c478bd9Sstevel@tonic-gate int fd; 2817c478bd9Sstevel@tonic-gate struct stat64 statbuf; 2827c478bd9Sstevel@tonic-gate caddr_t addr; 2837c478bd9Sstevel@tonic-gate size_t buflen; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate fd = open(_ENCODING_ALIAS_PATH, O_RDONLY); 2867c478bd9Sstevel@tonic-gate if (fd == -1) { 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * if no alias file found, 2897c478bd9Sstevel@tonic-gate * errno will be set to EINVAL. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate errno = EINVAL; 2927c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate if (fstat64(fd, &statbuf) == -1) { 2957c478bd9Sstevel@tonic-gate (void) close(fd); 2967c478bd9Sstevel@tonic-gate /* use errno set by fstat64 */ 2977c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate buflen = (size_t)statbuf.st_size; 3007c478bd9Sstevel@tonic-gate addr = mmap(NULL, buflen, PROT_READ, MAP_SHARED, fd, 0); 3017c478bd9Sstevel@tonic-gate (void) close(fd); 3027c478bd9Sstevel@tonic-gate if (addr == MAP_FAILED) { 3037c478bd9Sstevel@tonic-gate /* use errno set by mmap */ 3047c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate p = (char *)addr; 3077c478bd9Sstevel@tonic-gate tolen = search_alias(&p, buflen, tocode); 3087c478bd9Sstevel@tonic-gate if (tolen) { 3097c478bd9Sstevel@tonic-gate to_canonical = alloca(tolen + 1); 3107c478bd9Sstevel@tonic-gate (void) memcpy(to_canonical, p, tolen); 3117c478bd9Sstevel@tonic-gate to_canonical[tolen] = '\0'; 3127c478bd9Sstevel@tonic-gate } else { 3137c478bd9Sstevel@tonic-gate to_canonical = (char *)tocode; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate p = (char *)addr; 3167c478bd9Sstevel@tonic-gate fromlen = search_alias(&p, buflen, fromcode); 3177c478bd9Sstevel@tonic-gate if (fromlen) { 3187c478bd9Sstevel@tonic-gate from_canonical = alloca(fromlen + 1); 3197c478bd9Sstevel@tonic-gate (void) memcpy(from_canonical, p, fromlen); 3207c478bd9Sstevel@tonic-gate from_canonical[fromlen] = '\0'; 3217c478bd9Sstevel@tonic-gate } else { 3227c478bd9Sstevel@tonic-gate from_canonical = (char *)fromcode; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate (void) munmap(addr, buflen); 3257c478bd9Sstevel@tonic-gate if (tolen == 0 && fromlen == 0) { 3267c478bd9Sstevel@tonic-gate errno = EINVAL; 3277c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate cv = iconv_open_all(to_canonical, from_canonical, ipath); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* errno set by iconv_open_all on error */ 3337c478bd9Sstevel@tonic-gate return (cv); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate static iconv_p 3377c478bd9Sstevel@tonic-gate iconv_open_private(const char *lib, const char *tbl) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate iconv_t (*fptr)(const char *); 3407c478bd9Sstevel@tonic-gate iconv_p cdpath; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if ((cdpath = malloc(sizeof (struct _iconv_fields))) == NULL) 3437c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if ((cdpath->_icv_handle = dlopen(lib, RTLD_LAZY)) == 0) { 3467c478bd9Sstevel@tonic-gate free(cdpath); 3477c478bd9Sstevel@tonic-gate /* dlopen does not define error no */ 3487c478bd9Sstevel@tonic-gate errno = EINVAL; 3497c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* gets address of _icv_open */ 3537c478bd9Sstevel@tonic-gate if ((fptr = (iconv_t(*)(const char *))dlsym(cdpath->_icv_handle, 3547c478bd9Sstevel@tonic-gate "_icv_open")) == NULL) { 3557c478bd9Sstevel@tonic-gate (void) dlclose(cdpath->_icv_handle); 3567c478bd9Sstevel@tonic-gate free(cdpath); 3577c478bd9Sstevel@tonic-gate /* dlsym does not define errno */ 3587c478bd9Sstevel@tonic-gate errno = EINVAL; 3597c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * gets address of _icv_iconv in the loadable conversion module 3647c478bd9Sstevel@tonic-gate * and stores it in cdpath->_icv_iconv 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if ((cdpath->_icv_iconv = (size_t(*)(iconv_t, const char **, 3687c478bd9Sstevel@tonic-gate size_t *, char **, size_t *))dlsym(cdpath->_icv_handle, 3697c478bd9Sstevel@tonic-gate "_icv_iconv")) == NULL) { 3707c478bd9Sstevel@tonic-gate (void) dlclose(cdpath->_icv_handle); 3717c478bd9Sstevel@tonic-gate free(cdpath); 3727c478bd9Sstevel@tonic-gate /* dlsym does not define errno */ 3737c478bd9Sstevel@tonic-gate errno = EINVAL; 3747c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * gets address of _icv_close in the loadable conversion module 3797c478bd9Sstevel@tonic-gate * and stores it in cd->_icv_close 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate if ((cdpath->_icv_close = (void(*)(iconv_t))dlsym(cdpath->_icv_handle, 3827c478bd9Sstevel@tonic-gate "_icv_close")) == NULL) { 3837c478bd9Sstevel@tonic-gate (void) dlclose(cdpath->_icv_handle); 3847c478bd9Sstevel@tonic-gate free(cdpath); 3857c478bd9Sstevel@tonic-gate /* dlsym does not define errno */ 3867c478bd9Sstevel@tonic-gate errno = EINVAL; 3877c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * initialize the state of the actual _icv_iconv conversion routine 3927c478bd9Sstevel@tonic-gate * For the normal iconv module, NULL will be passed as an argument 3937257d1b4Sraf * although the iconv_open() of the module won't use that. 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate cdpath->_icv_state = (void *)(*fptr)(tbl); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate if (cdpath->_icv_state == (struct _icv_state *)-1) { 3987c478bd9Sstevel@tonic-gate (void) dlclose(cdpath->_icv_handle); 3997c478bd9Sstevel@tonic-gate free(cdpath); 4007c478bd9Sstevel@tonic-gate /* this module does not satisfy this conversion */ 4017c478bd9Sstevel@tonic-gate errno = EINVAL; 4027c478bd9Sstevel@tonic-gate return ((iconv_p)-1); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate return (cdpath); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate int 4097257d1b4Sraf iconv_close(iconv_t cd) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate if (cd == NULL) { 4127c478bd9Sstevel@tonic-gate errno = EBADF; 4137c478bd9Sstevel@tonic-gate return (-1); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate (*(cd->_conv)->_icv_close)(cd->_conv->_icv_state); 416b8d94837SIenup Sung if (cd->_conv->_icv_handle != NULL) 4177c478bd9Sstevel@tonic-gate (void) dlclose(cd->_conv->_icv_handle); 4187c478bd9Sstevel@tonic-gate free(cd->_conv); 4197c478bd9Sstevel@tonic-gate free(cd); 4207c478bd9Sstevel@tonic-gate return (0); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 423b8d94837SIenup Sung /* 424b8d94837SIenup Sung * To have minimal performance impact to the existing run-time behavior, 425b8d94837SIenup Sung * we supply a dummy passthru_icv_close() that will just return. 426b8d94837SIenup Sung */ 427b8d94837SIenup Sung static void 428b8d94837SIenup Sung /*LINTED E_FUNC_ARG_UNUSED*/ 429b8d94837SIenup Sung passthru_icv_close(iconv_t cd) 430b8d94837SIenup Sung { 431b8d94837SIenup Sung } 432b8d94837SIenup Sung 4337c478bd9Sstevel@tonic-gate size_t 4347257d1b4Sraf iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, 4357c478bd9Sstevel@tonic-gate char **outbuf, size_t *outbytesleft) 4367c478bd9Sstevel@tonic-gate { 4377c478bd9Sstevel@tonic-gate /* check if cd is valid */ 438*5f7cdf77SKeith M Wesolowski if (cd == NULL || cd == (iconv_t)-1) { 4397c478bd9Sstevel@tonic-gate errno = EBADF; 4407c478bd9Sstevel@tonic-gate return ((size_t)-1); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* direct conversion */ 4447c478bd9Sstevel@tonic-gate return ((*(cd->_conv)->_icv_iconv)(cd->_conv->_icv_state, 4457c478bd9Sstevel@tonic-gate inbuf, inbytesleft, outbuf, outbytesleft)); 4467c478bd9Sstevel@tonic-gate } 447b8d94837SIenup Sung 448b8d94837SIenup Sung static size_t 449b8d94837SIenup Sung passthru_icv_iconv(iconv_t cd, const char **inbuf, size_t *inbufleft, 450b8d94837SIenup Sung char **outbuf, size_t *outbufleft) 451b8d94837SIenup Sung { 452b8d94837SIenup Sung size_t ibl; 453b8d94837SIenup Sung size_t obl; 454b8d94837SIenup Sung size_t len; 455b8d94837SIenup Sung size_t ret_val; 456b8d94837SIenup Sung 457b8d94837SIenup Sung /* Check if the conversion descriptor is a valid one. */ 458b8d94837SIenup Sung if (cd != (iconv_t)PASSTHRU_MAGIC_NUMBER) { 459b8d94837SIenup Sung errno = EBADF; 460b8d94837SIenup Sung return ((size_t)-1); 461b8d94837SIenup Sung } 462b8d94837SIenup Sung 463b8d94837SIenup Sung /* For any state reset request, return success. */ 464b8d94837SIenup Sung if (inbuf == NULL || *inbuf == NULL) 465b8d94837SIenup Sung return (0); 466b8d94837SIenup Sung 467b8d94837SIenup Sung /* 468b8d94837SIenup Sung * Initialize internally used variables for a better performance 469b8d94837SIenup Sung * and prepare for a couple of the return values before the actual 470b8d94837SIenup Sung * copying of the bytes. 471b8d94837SIenup Sung */ 472b8d94837SIenup Sung ibl = *inbufleft; 473b8d94837SIenup Sung obl = *outbufleft; 474b8d94837SIenup Sung 475b8d94837SIenup Sung if (ibl > obl) { 476b8d94837SIenup Sung len = obl; 477b8d94837SIenup Sung errno = E2BIG; 478b8d94837SIenup Sung ret_val = (size_t)-1; 479b8d94837SIenup Sung } else { 480b8d94837SIenup Sung len = ibl; 481b8d94837SIenup Sung ret_val = 0; 482b8d94837SIenup Sung } 483b8d94837SIenup Sung 484b8d94837SIenup Sung /* 485b8d94837SIenup Sung * Do the copy using memmove(). There are no EILSEQ or EINVAL 486b8d94837SIenup Sung * checkings since this is a simple copying. 487b8d94837SIenup Sung */ 488b8d94837SIenup Sung (void) memmove((void *)*outbuf, (const void *)*inbuf, len); 489b8d94837SIenup Sung 490b8d94837SIenup Sung /* Update the return values related to the buffers then do return. */ 491b8d94837SIenup Sung *inbuf = *inbuf + len; 492b8d94837SIenup Sung *outbuf = *outbuf + len; 493b8d94837SIenup Sung *inbufleft = ibl - len; 494b8d94837SIenup Sung *outbufleft = obl - len; 495b8d94837SIenup Sung 496b8d94837SIenup Sung return (ret_val); 497b8d94837SIenup Sung } 498