1*0d5acd74SJohn Marino /*********************************************************** 2*0d5acd74SJohn Marino Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. 3*0d5acd74SJohn Marino Copyright 2010, Gabor Kovesdan <gabor@FreeBSD.org> 4*0d5acd74SJohn Marino 5*0d5acd74SJohn Marino All Rights Reserved 6*0d5acd74SJohn Marino 7*0d5acd74SJohn Marino Permission to use, copy, modify, and distribute this software and its 8*0d5acd74SJohn Marino documentation for any purpose and without fee is hereby granted, 9*0d5acd74SJohn Marino provided that the above copyright notice appear in all copies and that 10*0d5acd74SJohn Marino both that copyright notice and this permission notice appear in 11*0d5acd74SJohn Marino supporting documentation, and that Alfalfa's name not be used in 12*0d5acd74SJohn Marino advertising or publicity pertaining to distribution of the software 13*0d5acd74SJohn Marino without specific, written prior permission. 14*0d5acd74SJohn Marino 15*0d5acd74SJohn Marino ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 16*0d5acd74SJohn Marino ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 17*0d5acd74SJohn Marino ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 18*0d5acd74SJohn Marino ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 19*0d5acd74SJohn Marino WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 20*0d5acd74SJohn Marino ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 21*0d5acd74SJohn Marino SOFTWARE. 22*0d5acd74SJohn Marino 23*0d5acd74SJohn Marino If you make any modifications, bugfixes or other changes to this software 24*0d5acd74SJohn Marino we'd appreciate it if you could send a copy to us so we can keep things 25*0d5acd74SJohn Marino up-to-date. Many thanks. 26*0d5acd74SJohn Marino Kee Hinckley 27*0d5acd74SJohn Marino Alfalfa Software, Inc. 28*0d5acd74SJohn Marino 267 Allston St., #3 29*0d5acd74SJohn Marino Cambridge, MA 02139 USA 30*0d5acd74SJohn Marino nazgul@alfalfa.com 31*0d5acd74SJohn Marino 32*0d5acd74SJohn Marino $FreeBSD: head/lib/libc/nls/msgcat.c 244358 2012-12-17 12:57:36Z eadler $ 33*0d5acd74SJohn Marino ******************************************************************/ 34*0d5acd74SJohn Marino 35*0d5acd74SJohn Marino #define _NLS_PRIVATE 36*0d5acd74SJohn Marino 37*0d5acd74SJohn Marino #include "namespace.h" 38*0d5acd74SJohn Marino #include <sys/types.h> 39*0d5acd74SJohn Marino #include <sys/stat.h> 40*0d5acd74SJohn Marino #include <sys/mman.h> 41*0d5acd74SJohn Marino #include <sys/queue.h> 42*0d5acd74SJohn Marino 43*0d5acd74SJohn Marino #include <arpa/inet.h> /* for ntohl() */ 44*0d5acd74SJohn Marino 45*0d5acd74SJohn Marino #include <errno.h> 46*0d5acd74SJohn Marino #include <fcntl.h> 47*0d5acd74SJohn Marino #include <limits.h> 48*0d5acd74SJohn Marino #include <locale.h> 49*0d5acd74SJohn Marino #include <nl_types.h> 50*0d5acd74SJohn Marino #include <pthread.h> 51*0d5acd74SJohn Marino #include <stdio.h> 52*0d5acd74SJohn Marino #include <stdlib.h> 53*0d5acd74SJohn Marino #include <string.h> 54*0d5acd74SJohn Marino #include <unistd.h> 55*0d5acd74SJohn Marino #include "un-namespace.h" 56*0d5acd74SJohn Marino 57*0d5acd74SJohn Marino #include "../locale/setlocale.h" /* for ENCODING_LEN */ 58*0d5acd74SJohn Marino 59*0d5acd74SJohn Marino #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" 60*0d5acd74SJohn Marino 61*0d5acd74SJohn Marino #define RLOCK(fail) { int ret; \ 62*0d5acd74SJohn Marino if (__isthreaded && \ 63*0d5acd74SJohn Marino ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ 64*0d5acd74SJohn Marino errno = ret; \ 65*0d5acd74SJohn Marino return (fail); \ 66*0d5acd74SJohn Marino }} 67*0d5acd74SJohn Marino #define WLOCK(fail) { int ret; \ 68*0d5acd74SJohn Marino if (__isthreaded && \ 69*0d5acd74SJohn Marino ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ 70*0d5acd74SJohn Marino errno = ret; \ 71*0d5acd74SJohn Marino return (fail); \ 72*0d5acd74SJohn Marino }} 73*0d5acd74SJohn Marino #define UNLOCK { if (__isthreaded) \ 74*0d5acd74SJohn Marino _pthread_rwlock_unlock(&rwlock); } 75*0d5acd74SJohn Marino 76*0d5acd74SJohn Marino #define NLERR ((nl_catd) -1) 77*0d5acd74SJohn Marino #define NLRETERR(errc) { errno = errc; return (NLERR); } 78*0d5acd74SJohn Marino #define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ 79*0d5acd74SJohn Marino np = malloc(sizeof(struct catentry)); \ 80*0d5acd74SJohn Marino if (np != NULL) { \ 81*0d5acd74SJohn Marino np->name = strdup(n); \ 82*0d5acd74SJohn Marino np->path = NULL; \ 83*0d5acd74SJohn Marino np->catd = NLERR; \ 84*0d5acd74SJohn Marino np->lang = (l == NULL) ? NULL : \ 85*0d5acd74SJohn Marino strdup(l); \ 86*0d5acd74SJohn Marino np->caterrno = e; \ 87*0d5acd74SJohn Marino SLIST_INSERT_HEAD(&cache, np, list); \ 88*0d5acd74SJohn Marino } \ 89*0d5acd74SJohn Marino UNLOCK; \ 90*0d5acd74SJohn Marino errno = e; \ 91*0d5acd74SJohn Marino } 92*0d5acd74SJohn Marino 93*0d5acd74SJohn Marino static nl_catd load_msgcat(const char *, const char *, const char *); 94*0d5acd74SJohn Marino 95*0d5acd74SJohn Marino static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 96*0d5acd74SJohn Marino 97*0d5acd74SJohn Marino struct catentry { 98*0d5acd74SJohn Marino SLIST_ENTRY(catentry) list; 99*0d5acd74SJohn Marino char *name; 100*0d5acd74SJohn Marino char *path; 101*0d5acd74SJohn Marino int caterrno; 102*0d5acd74SJohn Marino nl_catd catd; 103*0d5acd74SJohn Marino char *lang; 104*0d5acd74SJohn Marino int refcount; 105*0d5acd74SJohn Marino }; 106*0d5acd74SJohn Marino 107*0d5acd74SJohn Marino SLIST_HEAD(listhead, catentry) cache = 108*0d5acd74SJohn Marino SLIST_HEAD_INITIALIZER(cache); 109*0d5acd74SJohn Marino 110*0d5acd74SJohn Marino nl_catd 111*0d5acd74SJohn Marino catopen(const char *name, int type) 112*0d5acd74SJohn Marino { 113*0d5acd74SJohn Marino struct stat sbuf; 114*0d5acd74SJohn Marino struct catentry *np; 115*0d5acd74SJohn Marino char *base, *cptr, *cptr1, *lang, *nlspath, *pathP, *pcode; 116*0d5acd74SJohn Marino char *plang, *pter, *tmpptr; 117*0d5acd74SJohn Marino int saverr, spcleft; 118*0d5acd74SJohn Marino char path[PATH_MAX]; 119*0d5acd74SJohn Marino 120*0d5acd74SJohn Marino /* sanity checking */ 121*0d5acd74SJohn Marino if (name == NULL || *name == '\0') 122*0d5acd74SJohn Marino NLRETERR(EINVAL); 123*0d5acd74SJohn Marino 124*0d5acd74SJohn Marino if (strchr(name, '/') != NULL) 125*0d5acd74SJohn Marino /* have a pathname */ 126*0d5acd74SJohn Marino lang = NULL; 127*0d5acd74SJohn Marino else { 128*0d5acd74SJohn Marino if (type == NL_CAT_LOCALE) 129*0d5acd74SJohn Marino lang = setlocale(LC_MESSAGES, NULL); 130*0d5acd74SJohn Marino else 131*0d5acd74SJohn Marino lang = getenv("LANG"); 132*0d5acd74SJohn Marino 133*0d5acd74SJohn Marino if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN || 134*0d5acd74SJohn Marino (lang[0] == '.' && 135*0d5acd74SJohn Marino (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || 136*0d5acd74SJohn Marino strchr(lang, '/') != NULL) 137*0d5acd74SJohn Marino lang = "C"; 138*0d5acd74SJohn Marino } 139*0d5acd74SJohn Marino 140*0d5acd74SJohn Marino /* Try to get it from the cache first */ 141*0d5acd74SJohn Marino RLOCK(NLERR); 142*0d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 143*0d5acd74SJohn Marino if ((strcmp(np->name, name) == 0) && 144*0d5acd74SJohn Marino ((lang != NULL && np->lang != NULL && 145*0d5acd74SJohn Marino strcmp(np->lang, lang) == 0) || (np->lang == lang))) { 146*0d5acd74SJohn Marino if (np->caterrno != 0) { 147*0d5acd74SJohn Marino /* Found cached failing entry */ 148*0d5acd74SJohn Marino UNLOCK; 149*0d5acd74SJohn Marino NLRETERR(np->caterrno); 150*0d5acd74SJohn Marino } else { 151*0d5acd74SJohn Marino /* Found cached successful entry */ 152*0d5acd74SJohn Marino np->refcount++; 153*0d5acd74SJohn Marino UNLOCK; 154*0d5acd74SJohn Marino return (np->catd); 155*0d5acd74SJohn Marino } 156*0d5acd74SJohn Marino } 157*0d5acd74SJohn Marino } 158*0d5acd74SJohn Marino UNLOCK; 159*0d5acd74SJohn Marino 160*0d5acd74SJohn Marino /* is it absolute path ? if yes, load immediately */ 161*0d5acd74SJohn Marino if (strchr(name, '/') != NULL) 162*0d5acd74SJohn Marino return (load_msgcat(name, name, lang)); 163*0d5acd74SJohn Marino 164*0d5acd74SJohn Marino /* sanity checking */ 165*0d5acd74SJohn Marino if ((plang = cptr1 = strdup(lang)) == NULL) 166*0d5acd74SJohn Marino return (NLERR); 167*0d5acd74SJohn Marino if ((cptr = strchr(cptr1, '@')) != NULL) 168*0d5acd74SJohn Marino *cptr = '\0'; 169*0d5acd74SJohn Marino pter = pcode = ""; 170*0d5acd74SJohn Marino if ((cptr = strchr(cptr1, '_')) != NULL) { 171*0d5acd74SJohn Marino *cptr++ = '\0'; 172*0d5acd74SJohn Marino pter = cptr1 = cptr; 173*0d5acd74SJohn Marino } 174*0d5acd74SJohn Marino if ((cptr = strchr(cptr1, '.')) != NULL) { 175*0d5acd74SJohn Marino *cptr++ = '\0'; 176*0d5acd74SJohn Marino pcode = cptr; 177*0d5acd74SJohn Marino } 178*0d5acd74SJohn Marino 179*0d5acd74SJohn Marino if ((nlspath = getenv("NLSPATH")) == NULL || issetugid()) 180*0d5acd74SJohn Marino nlspath = _DEFAULT_NLS_PATH; 181*0d5acd74SJohn Marino 182*0d5acd74SJohn Marino if ((base = cptr = strdup(nlspath)) == NULL) { 183*0d5acd74SJohn Marino saverr = errno; 184*0d5acd74SJohn Marino free(plang); 185*0d5acd74SJohn Marino errno = saverr; 186*0d5acd74SJohn Marino return (NLERR); 187*0d5acd74SJohn Marino } 188*0d5acd74SJohn Marino 189*0d5acd74SJohn Marino while ((nlspath = strsep(&cptr, ":")) != NULL) { 190*0d5acd74SJohn Marino pathP = path; 191*0d5acd74SJohn Marino if (*nlspath) { 192*0d5acd74SJohn Marino for (; *nlspath; ++nlspath) { 193*0d5acd74SJohn Marino if (*nlspath == '%') { 194*0d5acd74SJohn Marino switch (*(nlspath + 1)) { 195*0d5acd74SJohn Marino case 'l': 196*0d5acd74SJohn Marino tmpptr = plang; 197*0d5acd74SJohn Marino break; 198*0d5acd74SJohn Marino case 't': 199*0d5acd74SJohn Marino tmpptr = pter; 200*0d5acd74SJohn Marino break; 201*0d5acd74SJohn Marino case 'c': 202*0d5acd74SJohn Marino tmpptr = pcode; 203*0d5acd74SJohn Marino break; 204*0d5acd74SJohn Marino case 'L': 205*0d5acd74SJohn Marino tmpptr = lang; 206*0d5acd74SJohn Marino break; 207*0d5acd74SJohn Marino case 'N': 208*0d5acd74SJohn Marino tmpptr = (char *)name; 209*0d5acd74SJohn Marino break; 210*0d5acd74SJohn Marino case '%': 211*0d5acd74SJohn Marino ++nlspath; 212*0d5acd74SJohn Marino /* FALLTHROUGH */ 213*0d5acd74SJohn Marino default: 214*0d5acd74SJohn Marino if (pathP - path >= 215*0d5acd74SJohn Marino sizeof(path) - 1) 216*0d5acd74SJohn Marino goto too_long; 217*0d5acd74SJohn Marino *(pathP++) = *nlspath; 218*0d5acd74SJohn Marino continue; 219*0d5acd74SJohn Marino } 220*0d5acd74SJohn Marino ++nlspath; 221*0d5acd74SJohn Marino put_tmpptr: 222*0d5acd74SJohn Marino spcleft = sizeof(path) - 223*0d5acd74SJohn Marino (pathP - path) - 1; 224*0d5acd74SJohn Marino if (strlcpy(pathP, tmpptr, spcleft) >= 225*0d5acd74SJohn Marino spcleft) { 226*0d5acd74SJohn Marino too_long: 227*0d5acd74SJohn Marino free(plang); 228*0d5acd74SJohn Marino free(base); 229*0d5acd74SJohn Marino SAVEFAIL(name, lang, ENAMETOOLONG); 230*0d5acd74SJohn Marino NLRETERR(ENAMETOOLONG); 231*0d5acd74SJohn Marino } 232*0d5acd74SJohn Marino pathP += strlen(tmpptr); 233*0d5acd74SJohn Marino } else { 234*0d5acd74SJohn Marino if (pathP - path >= sizeof(path) - 1) 235*0d5acd74SJohn Marino goto too_long; 236*0d5acd74SJohn Marino *(pathP++) = *nlspath; 237*0d5acd74SJohn Marino } 238*0d5acd74SJohn Marino } 239*0d5acd74SJohn Marino *pathP = '\0'; 240*0d5acd74SJohn Marino if (stat(path, &sbuf) == 0) { 241*0d5acd74SJohn Marino free(plang); 242*0d5acd74SJohn Marino free(base); 243*0d5acd74SJohn Marino return (load_msgcat(path, name, lang)); 244*0d5acd74SJohn Marino } 245*0d5acd74SJohn Marino } else { 246*0d5acd74SJohn Marino tmpptr = (char *)name; 247*0d5acd74SJohn Marino --nlspath; 248*0d5acd74SJohn Marino goto put_tmpptr; 249*0d5acd74SJohn Marino } 250*0d5acd74SJohn Marino } 251*0d5acd74SJohn Marino free(plang); 252*0d5acd74SJohn Marino free(base); 253*0d5acd74SJohn Marino SAVEFAIL(name, lang, ENOENT); 254*0d5acd74SJohn Marino NLRETERR(ENOENT); 255*0d5acd74SJohn Marino } 256*0d5acd74SJohn Marino 257*0d5acd74SJohn Marino char * 258*0d5acd74SJohn Marino catgets(nl_catd catd, int set_id, int msg_id, const char *s) 259*0d5acd74SJohn Marino { 260*0d5acd74SJohn Marino struct _nls_cat_hdr *cat_hdr; 261*0d5acd74SJohn Marino struct _nls_msg_hdr *msg_hdr; 262*0d5acd74SJohn Marino struct _nls_set_hdr *set_hdr; 263*0d5acd74SJohn Marino int i, l, r, u; 264*0d5acd74SJohn Marino 265*0d5acd74SJohn Marino if (catd == NULL || catd == NLERR) { 266*0d5acd74SJohn Marino errno = EBADF; 267*0d5acd74SJohn Marino /* LINTED interface problem */ 268*0d5acd74SJohn Marino return ((char *)s); 269*0d5acd74SJohn Marino } 270*0d5acd74SJohn Marino 271*0d5acd74SJohn Marino cat_hdr = (struct _nls_cat_hdr *)catd->__data; 272*0d5acd74SJohn Marino set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data + 273*0d5acd74SJohn Marino sizeof(struct _nls_cat_hdr)); 274*0d5acd74SJohn Marino 275*0d5acd74SJohn Marino /* binary search, see knuth algorithm b */ 276*0d5acd74SJohn Marino l = 0; 277*0d5acd74SJohn Marino u = ntohl((u_int32_t)cat_hdr->__nsets) - 1; 278*0d5acd74SJohn Marino while (l <= u) { 279*0d5acd74SJohn Marino i = (l + u) / 2; 280*0d5acd74SJohn Marino r = set_id - ntohl((u_int32_t)set_hdr[i].__setno); 281*0d5acd74SJohn Marino 282*0d5acd74SJohn Marino if (r == 0) { 283*0d5acd74SJohn Marino msg_hdr = (struct _nls_msg_hdr *) 284*0d5acd74SJohn Marino (void *)((char *)catd->__data + 285*0d5acd74SJohn Marino sizeof(struct _nls_cat_hdr) + 286*0d5acd74SJohn Marino ntohl((u_int32_t)cat_hdr->__msg_hdr_offset)); 287*0d5acd74SJohn Marino 288*0d5acd74SJohn Marino l = ntohl((u_int32_t)set_hdr[i].__index); 289*0d5acd74SJohn Marino u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1; 290*0d5acd74SJohn Marino while (l <= u) { 291*0d5acd74SJohn Marino i = (l + u) / 2; 292*0d5acd74SJohn Marino r = msg_id - 293*0d5acd74SJohn Marino ntohl((u_int32_t)msg_hdr[i].__msgno); 294*0d5acd74SJohn Marino if (r == 0) { 295*0d5acd74SJohn Marino return ((char *) catd->__data + 296*0d5acd74SJohn Marino sizeof(struct _nls_cat_hdr) + 297*0d5acd74SJohn Marino ntohl((u_int32_t) 298*0d5acd74SJohn Marino cat_hdr->__msg_txt_offset) + 299*0d5acd74SJohn Marino ntohl((u_int32_t) 300*0d5acd74SJohn Marino msg_hdr[i].__offset)); 301*0d5acd74SJohn Marino } else if (r < 0) { 302*0d5acd74SJohn Marino u = i - 1; 303*0d5acd74SJohn Marino } else { 304*0d5acd74SJohn Marino l = i + 1; 305*0d5acd74SJohn Marino } 306*0d5acd74SJohn Marino } 307*0d5acd74SJohn Marino 308*0d5acd74SJohn Marino /* not found */ 309*0d5acd74SJohn Marino goto notfound; 310*0d5acd74SJohn Marino 311*0d5acd74SJohn Marino } else if (r < 0) { 312*0d5acd74SJohn Marino u = i - 1; 313*0d5acd74SJohn Marino } else { 314*0d5acd74SJohn Marino l = i + 1; 315*0d5acd74SJohn Marino } 316*0d5acd74SJohn Marino } 317*0d5acd74SJohn Marino 318*0d5acd74SJohn Marino notfound: 319*0d5acd74SJohn Marino /* not found */ 320*0d5acd74SJohn Marino errno = ENOMSG; 321*0d5acd74SJohn Marino /* LINTED interface problem */ 322*0d5acd74SJohn Marino return ((char *)s); 323*0d5acd74SJohn Marino } 324*0d5acd74SJohn Marino 325*0d5acd74SJohn Marino int 326*0d5acd74SJohn Marino catclose(nl_catd catd) 327*0d5acd74SJohn Marino { 328*0d5acd74SJohn Marino struct catentry *np; 329*0d5acd74SJohn Marino 330*0d5acd74SJohn Marino /* sanity checking */ 331*0d5acd74SJohn Marino if (catd == NULL || catd == NLERR) { 332*0d5acd74SJohn Marino errno = EBADF; 333*0d5acd74SJohn Marino return (-1); 334*0d5acd74SJohn Marino } 335*0d5acd74SJohn Marino 336*0d5acd74SJohn Marino /* Remove from cache if not referenced any more */ 337*0d5acd74SJohn Marino WLOCK(-1); 338*0d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 339*0d5acd74SJohn Marino if (catd == np->catd) { 340*0d5acd74SJohn Marino np->refcount--; 341*0d5acd74SJohn Marino if (np->refcount == 0) { 342*0d5acd74SJohn Marino munmap(catd->__data, (size_t)catd->__size); 343*0d5acd74SJohn Marino free(catd); 344*0d5acd74SJohn Marino SLIST_REMOVE(&cache, np, catentry, list); 345*0d5acd74SJohn Marino free(np->name); 346*0d5acd74SJohn Marino free(np->path); 347*0d5acd74SJohn Marino free(np->lang); 348*0d5acd74SJohn Marino free(np); 349*0d5acd74SJohn Marino } 350*0d5acd74SJohn Marino break; 351*0d5acd74SJohn Marino } 352*0d5acd74SJohn Marino } 353*0d5acd74SJohn Marino UNLOCK; 354*0d5acd74SJohn Marino return (0); 355*0d5acd74SJohn Marino } 356*0d5acd74SJohn Marino 357*0d5acd74SJohn Marino /* 358*0d5acd74SJohn Marino * Internal support functions 359*0d5acd74SJohn Marino */ 360*0d5acd74SJohn Marino 361*0d5acd74SJohn Marino static nl_catd 362*0d5acd74SJohn Marino load_msgcat(const char *path, const char *name, const char *lang) 363*0d5acd74SJohn Marino { 364*0d5acd74SJohn Marino struct stat st; 365*0d5acd74SJohn Marino nl_catd catd; 366*0d5acd74SJohn Marino struct catentry *np; 367*0d5acd74SJohn Marino void *data; 368*0d5acd74SJohn Marino int fd; 369*0d5acd74SJohn Marino 370*0d5acd74SJohn Marino /* path/name will never be NULL here */ 371*0d5acd74SJohn Marino 372*0d5acd74SJohn Marino /* 373*0d5acd74SJohn Marino * One more try in cache; if it was not found by name, 374*0d5acd74SJohn Marino * it might still be found by absolute path. 375*0d5acd74SJohn Marino */ 376*0d5acd74SJohn Marino RLOCK(NLERR); 377*0d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 378*0d5acd74SJohn Marino if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { 379*0d5acd74SJohn Marino np->refcount++; 380*0d5acd74SJohn Marino UNLOCK; 381*0d5acd74SJohn Marino return (np->catd); 382*0d5acd74SJohn Marino } 383*0d5acd74SJohn Marino } 384*0d5acd74SJohn Marino UNLOCK; 385*0d5acd74SJohn Marino 386*0d5acd74SJohn Marino if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { 387*0d5acd74SJohn Marino SAVEFAIL(name, lang, errno); 388*0d5acd74SJohn Marino NLRETERR(errno); 389*0d5acd74SJohn Marino } 390*0d5acd74SJohn Marino 391*0d5acd74SJohn Marino if (_fstat(fd, &st) != 0) { 392*0d5acd74SJohn Marino _close(fd); 393*0d5acd74SJohn Marino SAVEFAIL(name, lang, EFTYPE); 394*0d5acd74SJohn Marino NLRETERR(EFTYPE); 395*0d5acd74SJohn Marino } 396*0d5acd74SJohn Marino 397*0d5acd74SJohn Marino /* 398*0d5acd74SJohn Marino * If the file size cannot be held in size_t we cannot mmap() 399*0d5acd74SJohn Marino * it to the memory. Probably, this will not be a problem given 400*0d5acd74SJohn Marino * that catalog files are usually small. 401*0d5acd74SJohn Marino */ 402*0d5acd74SJohn Marino if (st.st_size > SIZE_T_MAX) { 403*0d5acd74SJohn Marino _close(fd); 404*0d5acd74SJohn Marino SAVEFAIL(name, lang, EFBIG); 405*0d5acd74SJohn Marino NLRETERR(EFBIG); 406*0d5acd74SJohn Marino } 407*0d5acd74SJohn Marino 408*0d5acd74SJohn Marino if ((data = mmap(0, (size_t)st.st_size, PROT_READ, 409*0d5acd74SJohn Marino MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) { 410*0d5acd74SJohn Marino int saved_errno = errno; 411*0d5acd74SJohn Marino _close(fd); 412*0d5acd74SJohn Marino SAVEFAIL(name, lang, saved_errno); 413*0d5acd74SJohn Marino NLRETERR(saved_errno); 414*0d5acd74SJohn Marino } 415*0d5acd74SJohn Marino _close(fd); 416*0d5acd74SJohn Marino 417*0d5acd74SJohn Marino if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != 418*0d5acd74SJohn Marino _NLS_MAGIC) { 419*0d5acd74SJohn Marino munmap(data, (size_t)st.st_size); 420*0d5acd74SJohn Marino SAVEFAIL(name, lang, EFTYPE); 421*0d5acd74SJohn Marino NLRETERR(EFTYPE); 422*0d5acd74SJohn Marino } 423*0d5acd74SJohn Marino 424*0d5acd74SJohn Marino if ((catd = malloc(sizeof (*catd))) == NULL) { 425*0d5acd74SJohn Marino munmap(data, (size_t)st.st_size); 426*0d5acd74SJohn Marino SAVEFAIL(name, lang, ENOMEM); 427*0d5acd74SJohn Marino NLRETERR(ENOMEM); 428*0d5acd74SJohn Marino } 429*0d5acd74SJohn Marino 430*0d5acd74SJohn Marino catd->__data = data; 431*0d5acd74SJohn Marino catd->__size = (int)st.st_size; 432*0d5acd74SJohn Marino 433*0d5acd74SJohn Marino /* Caching opened catalog */ 434*0d5acd74SJohn Marino WLOCK(NLERR); 435*0d5acd74SJohn Marino if ((np = malloc(sizeof(struct catentry))) != NULL) { 436*0d5acd74SJohn Marino np->name = strdup(name); 437*0d5acd74SJohn Marino np->path = strdup(path); 438*0d5acd74SJohn Marino np->catd = catd; 439*0d5acd74SJohn Marino np->lang = (lang == NULL) ? NULL : strdup(lang); 440*0d5acd74SJohn Marino np->refcount = 1; 441*0d5acd74SJohn Marino np->caterrno = 0; 442*0d5acd74SJohn Marino SLIST_INSERT_HEAD(&cache, np, list); 443*0d5acd74SJohn Marino } 444*0d5acd74SJohn Marino UNLOCK; 445*0d5acd74SJohn Marino return (catd); 446*0d5acd74SJohn Marino } 447