1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  25  * Copyright 2016 Joyent, Inc.
  26  */
  27 
  28 /*
  29  * Implementation of all external interfaces between ld.so.1 and libc.
  30  *
  31  * This file started as a set of routines that provided synchronization and
  32  * locking operations using calls to libthread.  libthread has merged with libc
  33  * under the Unified Process Model (UPM), and things have gotten a lot simpler.
  34  * This file continues to establish and redirect various events within ld.so.1
  35  * to interfaces within libc.
  36  *
  37  * Until libc is loaded and relocated, any external interfaces are captured
  38  * locally.  Each link-map list maintains its own set of external vectors, as
  39  * each link-map list typically provides its own libc.  Although this per-link-
  40  * map list vectoring provides a degree of flexibility, there is a protocol
  41  * expected when calling various libc interfaces.
  42  *
  43  * i.   Any new alternative link-map list should call CI_THRINIT, and then call
  44  *      CI_TLS_MODADD to register any TLS for each object of that link-map list
  45  *      (this item is labeled i. as auditors can be the first objects loaded,
  46  *      and they exist on their own lik-map list).
  47  *
  48  * ii.  For the primary link-map list, CI_TLS_STATMOD must be called first to
  49  *      register any static TLS.  This routine is called regardless of there
  50  *      being any TLS, as this routine also establishes the link-map list as the
  51  *      primary list and fixes the association of uberdata).  CI_THRINIT should
  52  *      then be called.
  53  *
  54  * iii. Any objects added to an existing link-map list (primary or alternative)
  55  *      should call CI_TLS_MODADD to register any additional TLS.
  56  *
  57  * These events are established by:
  58  *
  59  * i.   Typically, libc is loaded as part of the primary dependencies of any
  60  *      link-map list (since the Unified Process Model (UPM), libc can't be
  61  *      lazily loaded).  To minimize the possibility of loading and registering
  62  *      objects, and then tearing them down (because of a relocation error),
  63  *      external vectors are established as part of load_completion().  This
  64  *      routine is called on completion of any operation that can cause objects
  65  *      to be loaded.  This point of control insures the objects have been fully
  66  *      analyzed and relocated, and moved to their controlling link-map list.
  67  *      The external vectors are established prior to any .inits being fired.
  68  *
  69  * ii.  Calls to CI_THRINIT, and CI_TLS_MODADD also occur as part of
  70  *      load_completion().  CI_THRINIT is only called once for each link-map
  71  *      control list.
  72  *
  73  * iii. Calls to CI_TLS_STATMOD, and CI_THRINIT occur for the primary link-map
  74  *      list in the final stages of setup().
  75  *
  76  * The interfaces provide by libc can be divided into two families.  The first
  77  * family consists of those interfaces that should be called from the link-map
  78  * list.  It's possible that these interfaces convey state concerning the
  79  * link-map list they are part of:
  80  *
  81  *      CI_ATEXIT
  82  *      CI TLS_MODADD
  83  *      CI_TLS_MODREM
  84  *      CI_TLS_STATMOD
  85  *      CI_THRINIT
  86  *
  87  * The second family are global in nature, that is, the link-map list from
  88  * which they are called provides no state information.  In fact, for
  89  * CI_BIND_GUARD, the calling link-map isn't even known.  The link-map can only
  90  * be deduced after ld.so.1's global lock has been obtained.  Therefore, the
  91  * following interfaces are also maintained as global:
  92  *
  93  *      CI_LCMESSAGES
  94  *      CI_BIND_GUARD
  95  *      CI_BIND_CLEAR
  96  *      CI_THR_SELF
  97  *
  98  * Note, it is possible that these global interfaces are obtained from an
  99  * alternative link-map list that gets torn down because of a processing
 100  * failure (unlikely, because the link-map list components must be analyzed
 101  * and relocated prior to load_completion(), but perhaps the tear down is still
 102  * a possibility).  Thus the global interfaces may have to be replaced.  Once
 103  * the interfaces have been obtained from the primary link-map, they can
 104  * remain fixed, as the primary link-map isn't going to go anywhere.
 105  *
 106  * The last wrinkle in the puzzle is what happens if an alternative link-map
 107  * is loaded with no libc dependency?  In this case, the alternative objects
 108  * can not call CI_THRINIT, can not be allowed to use TLS, and will not receive
 109  * any atexit processing.
 110  *
 111  * The history of these external interfaces is defined by their version:
 112  *
 113  * TI_VERSION == 1
 114  *      Under this model libthread provided rw_rwlock/rw_unlock, through which
 115  *      all rt_mutex_lock/rt_mutex_unlock calls were vectored.
 116  *      Under libc/libthread these interfaces provided _sigon/_sigoff (unlike
 117  *      lwp/libthread that provided signal blocking via bind_guard/bind_clear).
 118  *
 119  * TI_VERSION == 2
 120  *      Under this model only libthreads bind_guard/bind_clear and thr_self
 121  *      interfaces were used.  Both libthreads blocked signals under the
 122  *      bind_guard/bind_clear interfaces.   Lower level locking is derived
 123  *      from internally bound _lwp_ interfaces.  This removes recursive
 124  *      problems encountered when obtaining locking interfaces from libthread.
 125  *      The use of mutexes over reader/writer locks also enables the use of
 126  *      condition variables for controlling thread concurrency (allows access
 127  *      to objects only after their .init has completed).
 128  *
 129  * NOTE, the TI_VERSION indicated the ti_interface version number, where the
 130  * ti_interface was a large vector of functions passed to both libc (to override
 131  * the thread stub interfaces) and ld.so.1.  ld.so.1 used only a small subset of
 132  * these interfaces.
 133  *
 134  * CI_VERSION == 1
 135  *      Introduced with CI_VERSION & CI_ATEXIT
 136  *
 137  * CI_VERSION == 2 (Solaris 8 update 2).
 138  *      Added support for CI_LCMESSAGES
 139  *
 140  * CI_VERSION == 3 (Solaris 9).
 141  *      Added the following versions to the CI table:
 142  *
 143  *              CI_BIND_GUARD, CI_BIND_CLEAR, CI_THR_SELF
 144  *              CI_TLS_MODADD, CI_TLS_MOD_REMOVE, CI_TLS_STATMOD
 145  *
 146  *      This version introduced the DT_SUNW_RTLDINFO structure as a mechanism
 147  *      to handshake with ld.so.1.
 148  *
 149  * CI_VERSION == 4 (Solaris 10).
 150  *      Added the CI_THRINIT handshake as part of the libc/libthread unified
 151  *      process model.  libc now initializes the current thread pointer from
 152  *      this interface (and no longer relies on the INITFIRST flag - which
 153  *      others have started to camp out on).
 154  *
 155  * CI_VERSION == 5 (Solaris 11).
 156  *      Use of "protected" references within libc, so that symbols are
 157  *      pre-bound, and don't require ld.so.1 binding.  This implementation
 158  *      protects libc's critical regions from being vectored to auditors.
 159  *
 160  * CI_VERSION == 6 (Solaris 11).
 161  *      Added the CI_CRITICAL handshake, to allow "mem*" family to be reexposed
 162  *      as "global", and thus be redirected to auxiliary filters.
 163  *
 164  * Release summary:
 165  *
 166  *      Solaris 8       CI_ATEXIT via _ld_libc()
 167  *                      TI_* via _ld_concurrency()
 168  *
 169  *      Solaris 9       CI_ATEXIT and CI_LCMESSAGES via _ld_libc()
 170  *                      CI_* via RTLDINFO and _ld_libc()  - new libthread
 171  *                      TI_* via _ld_concurrency()  - old libthread
 172  *
 173  *      Solaris 10      CI_ATEXIT and CI_LCMESSAGES via _ld_libc()
 174  *                      CI_* via RTLDINFO and _ld_libc()  - new libthread
 175  */
 176 
 177 #include <sys/debug.h>
 178 #include <synch.h>
 179 #include <signal.h>
 180 #include <thread.h>
 181 #include <synch.h>
 182 #include <strings.h>
 183 #include <stdio.h>
 184 #include <libintl.h>
 185 #include <debug.h>
 186 #include <libc_int.h>
 187 #include "_elf.h"
 188 #include "_rtld.h"
 189 
 190 /*
 191  * This interface provides the unified process model communication between
 192  * ld.so.1 and libc.  This interface can be called a number of times:
 193  *
 194  *   -  Initially, this interface is called to process RTLDINFO.  This data
 195  *      structure is typically provided by libc, and contains the address of
 196  *      libc interfaces that must be called to initialize threads information.
 197  *
 198  *   -  _ld_libc(), this interface can also be called by libc at process
 199  *      initialization, after libc has been loaded and relocated, but before
 200  *      control has been passed to any user code (.init's or main()).  This
 201  *      call provides additional libc interface information that ld.so.1 must
 202  *      call during process execution.
 203  *
 204  *   -  _ld_libc() can also be called by libc during process execution to
 205  *      re-establish interfaces such as the locale.
 206  */
 207 static void
 208 get_lcinterface(Rt_map *lmp, Lc_interface *funcs)
 209 {
 210         int             threaded = 0, entry = 0, tag;
 211         Lm_list         *lml;
 212         Lc_desc         *lcp;
 213 
 214         if ((lmp == NULL) || (funcs == NULL))
 215                 return;
 216 
 217         /*
 218          * Once the process is active, ensure we grab a lock.
 219          */
 220         if (rtld_flags & RT_FL_APPLIC)
 221                 entry = enter(0);
 222 
 223         lml = LIST(lmp);
 224         lcp = &lml->lm_lcs[0];
 225 
 226         DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
 227 
 228         for (tag = funcs->ci_tag; tag; tag = (++funcs)->ci_tag) {
 229                 char    *gptr;
 230                 char    *lptr = funcs->ci_un.ci_ptr;
 231 
 232                 DBG_CALL(Dbg_util_lcinterface(lmp, tag, lptr));
 233 
 234                 if (tag >= CI_MAX)
 235                         continue;
 236 
 237                 /*
 238                  * Maintain all interfaces on a per-link-map basis.  Note, for
 239                  * most interfaces, only the first interface is used for any
 240                  * link-map list.  This prevents accidents with developers who
 241                  * manage to load two different versions of libc.
 242                  */
 243                 if ((lcp[tag].lc_lmp) &&
 244                     (tag != CI_LCMESSAGES) && (tag != CI_VERSION)) {
 245                         DBG_CALL(Dbg_unused_lcinterface(lmp,
 246                             lcp[tag].lc_lmp, tag));
 247                         continue;
 248                 }
 249 
 250                 lcp[tag].lc_un.lc_ptr = lptr;
 251                 lcp[tag].lc_lmp = lmp;
 252 
 253                 gptr = glcs[tag].lc_un.lc_ptr;
 254 
 255                 /*
 256                  * Process any interfaces that must be maintained on a global
 257                  * basis.
 258                  */
 259                 switch (tag) {
 260                 case CI_ATEXIT:
 261                         break;
 262 
 263                 case CI_LCMESSAGES:
 264                         /*
 265                          * At startup, ld.so.1 can establish a locale from one
 266                          * of the locale family of environment variables (see
 267                          * ld_str_env() and readenv_user()).  During process
 268                          * execution the locale can also be changed by the user.
 269                          * This interface is called from libc should the locale
 270                          * be modified.  Presently, only one global locale is
 271                          * maintained for all link-map lists, and only objects
 272                          * on the primrary link-map may change this locale.
 273                          */
 274                         if ((lml->lm_flags & LML_FLG_BASELM) &&
 275                             ((gptr == NULL) || (strcmp(gptr, lptr) != 0))) {
 276                                 /*
 277                                  * If we've obtained a message locale (typically
 278                                  * supplied via libc's setlocale()), then
 279                                  * register the locale for use in dgettext() so
 280                                  * as to reestablish the locale for ld.so.1's
 281                                  * messages.
 282                                  */
 283                                 if (gptr) {
 284                                         free((void *)gptr);
 285                                         rtld_flags |= RT_FL_NEWLOCALE;
 286                                 }
 287                                 glcs[tag].lc_un.lc_ptr = strdup(lptr);
 288 
 289                                 /*
 290                                  * Clear any cached messages.
 291                                  */
 292                                 bzero(err_strs, sizeof (err_strs));
 293                                 nosym_str = NULL;
 294                         }
 295                         break;
 296 
 297                 case CI_BIND_GUARD:
 298                 case CI_BIND_CLEAR:
 299                 case CI_THR_SELF:
 300                 case CI_CRITICAL:
 301                         /*
 302                          * If the global vector is unset, or this is the primary
 303                          * link-map, set the global vector.
 304                          */
 305                         if ((gptr == NULL) || (lml->lm_flags & LML_FLG_BASELM))
 306                                 glcs[tag].lc_un.lc_ptr = lptr;
 307 
 308                         /* FALLTHROUGH */
 309 
 310                 case CI_TLS_MODADD:
 311                 case CI_TLS_MODREM:
 312                 case CI_TLS_STATMOD:
 313                 case CI_THRINIT:
 314                         threaded++;
 315                         break;
 316 
 317                 case CI_VERSION:
 318                         if ((rtld_flags2 & RT_FL2_RTLDSEEN) == 0) {
 319                                 Aliste  idx;
 320                                 Lm_list *lml2;
 321                                 int     version;
 322 
 323                                 rtld_flags2 |= RT_FL2_RTLDSEEN;
 324 
 325                                 version = funcs->ci_un.ci_val;
 326 #if defined(CI_V_FIVE)
 327                                 if (version >= CI_V_FIVE) {
 328                                         thr_flg_nolock = THR_FLG_NOLOCK;
 329                                         thr_flg_reenter = THR_FLG_REENTER;
 330                                 }
 331 #endif
 332                                 if (version < CI_V_FOUR)
 333                                         break;
 334 
 335                                 rtld_flags2 |= RT_FL2_UNIFPROC;
 336 
 337                                 /*
 338                                  * We might have seen an auditor which is not
 339                                  * dependent on libc.  Such an auditor's link
 340                                  * map list has LML_FLG_HOLDLOCK set.  This
 341                                  * lock needs to be dropped.  Refer to
 342                                  * audit_setup() in audit.c.
 343                                  */
 344                                 if ((rtld_flags2 & RT_FL2_HASAUDIT) == 0)
 345                                         break;
 346 
 347                                 /*
 348                                  * Yes, we did.  Take care of them.
 349                                  */
 350                                 for (APLIST_TRAVERSE(dynlm_list, idx, lml2)) {
 351                                         Rt_map *map = (Rt_map *)lml2->lm_head;
 352 
 353                                         if (FLAGS(map) & FLG_RT_AUDIT) {
 354                                                 lml2->lm_flags &=
 355                                                     ~LML_FLG_HOLDLOCK;
 356                                         }
 357                                 }
 358                         }
 359                         break;
 360 
 361                 default:
 362                         break;
 363                 }
 364         }
 365 
 366         if (threaded) {
 367                 /*
 368                  * If a version of libc gives us only a subset of the TLS
 369                  * interfaces, it's confused and we discard the whole lot.
 370                  */
 371                 if ((lcp[CI_TLS_MODADD].lc_un.lc_func &&
 372                     lcp[CI_TLS_MODREM].lc_un.lc_func &&
 373                     lcp[CI_TLS_STATMOD].lc_un.lc_func) == NULL) {
 374                         lcp[CI_TLS_MODADD].lc_un.lc_func = NULL;
 375                         lcp[CI_TLS_MODREM].lc_un.lc_func = NULL;
 376                         lcp[CI_TLS_STATMOD].lc_un.lc_func = NULL;
 377                 }
 378 
 379                 /*
 380                  * Indicate that we're now thread capable.
 381                  */
 382                 if ((lml->lm_flags & LML_FLG_RTLDLM) == 0)
 383                         rtld_flags |= RT_FL_THREADS;
 384         }
 385 
 386         if (entry)
 387                 leave(lml, 0);
 388 }
 389 
 390 /*
 391  * At this point we know we have a set of objects that have been fully analyzed
 392  * and relocated.  Prior to the next major step of running .init sections (ie.
 393  * running user code), retrieve any RTLDINFO interfaces.
 394  */
 395 int
 396 rt_get_extern(Lm_list *lml, Rt_map *lmp)
 397 {
 398         if (lml->lm_rti) {
 399                 Aliste          idx;
 400                 Rti_desc        *rti;
 401 
 402                 for (ALIST_TRAVERSE(lml->lm_rti, idx, rti))
 403                         get_lcinterface(rti->rti_lmp, rti->rti_info);
 404 
 405                 free(lml->lm_rti);
 406                 lml->lm_rti = 0;
 407         }
 408 
 409         /*
 410          * Perform some sanity checks.  If we have TLS requirements we better
 411          * have the associated external interfaces.
 412          */
 413         if (lml->lm_tls &&
 414             (lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func == NULL)) {
 415                 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_NOSUPPORT),
 416                     NAME(lmp));
 417                 return (0);
 418         }
 419         return (1);
 420 }
 421 
 422 /*
 423  * Provide an interface for libc to communicate additional interface
 424  * information.
 425  */
 426 void
 427 _ld_libc(void *ptr)
 428 {
 429         get_lcinterface(_caller(caller(), CL_EXECDEF), (Lc_interface *)ptr);
 430 }
 431 
 432 static int      bindmask = 0;
 433 
 434 int
 435 rt_bind_guard(int flags)
 436 {
 437         int     (*fptr)(int);
 438         int     bindflag;
 439 
 440         if ((fptr = glcs[CI_BIND_GUARD].lc_un.lc_func) != NULL) {
 441                 return ((*fptr)(flags));
 442         } else {
 443                 bindflag = (flags & THR_FLG_RTLD);
 444                 if ((bindflag & bindmask) == 0) {
 445                         bindmask |= bindflag;
 446                         return (1);
 447                 }
 448                 return (0);
 449         }
 450 }
 451 
 452 int
 453 rt_bind_clear(int flags)
 454 {
 455         int     (*fptr)(int);
 456         int     bindflag;
 457 
 458         if ((fptr = glcs[CI_BIND_CLEAR].lc_un.lc_func) != NULL) {
 459                 return ((*fptr)(flags));
 460         } else {
 461                 bindflag = (flags & THR_FLG_RTLD);
 462                 if (bindflag == 0)
 463                         return (bindmask);
 464                 else {
 465                         bindmask &= ~bindflag;
 466                         return (0);
 467                 }
 468         }
 469 }
 470 
 471 /*
 472  * Make sure threads have been initialized.  This interface is called once for
 473  * each link-map list.
 474  */
 475 void
 476 rt_thr_init(Lm_list *lml)
 477 {
 478         void    (*fptr)(void);
 479 
 480         if ((fptr =
 481             (void (*)())lml->lm_lcs[CI_THRINIT].lc_un.lc_func) != NULL) {
 482                 lml->lm_lcs[CI_THRINIT].lc_un.lc_func = NULL;
 483 
 484                 leave(lml, thr_flg_reenter);
 485                 (*fptr)();
 486                 (void) enter(thr_flg_reenter);
 487 
 488                 /*
 489                  * If this is an alternative link-map list, and this is the
 490                  * first call to initialize threads, don't let the destination
 491                  * libc be deleted.  It is possible that an auditors complete
 492                  * initialization fails, but there is presently no main link-map
 493                  * list.  As this libc has established the thread pointer, don't
 494                  * delete this libc, otherwise the initialization of libc on the
 495                  * main link-map can be compromised during its threads
 496                  * initialization.
 497                  */
 498                 if (((lml->lm_flags & LML_FLG_BASELM) == 0) &&
 499                     ((rtld_flags2 & RT_FL2_PLMSETUP) == 0))
 500                         MODE(lml->lm_lcs[CI_THRINIT].lc_lmp) |= RTLD_NODELETE;
 501         }
 502 }
 503 
 504 thread_t
 505 rt_thr_self()
 506 {
 507         thread_t        (*fptr)(void);
 508 
 509         if ((fptr = (thread_t (*)())glcs[CI_THR_SELF].lc_un.lc_func) != NULL)
 510                 return ((*fptr)());
 511 
 512         return (1);
 513 }
 514 
 515 int
 516 rt_mutex_lock(Rt_lock *mp)
 517 {
 518         return (_lwp_mutex_lock((lwp_mutex_t *)mp));
 519 }
 520 
 521 int
 522 rt_mutex_unlock(Rt_lock *mp)
 523 {
 524         return (_lwp_mutex_unlock((lwp_mutex_t *)mp));
 525 }
 526 
 527 /*
 528  * Test whether we're in a libc critical region.  Certain function references,
 529  * like the "mem*" family, might require binding.  Although these functions can
 530  * safely bind to auxiliary filtees, they should not be captured by auditors.
 531  */
 532 int
 533 rt_critical()
 534 {
 535         int     (*fptr)(void);
 536 
 537         if ((fptr = glcs[CI_CRITICAL].lc_un.lc_func) != NULL)
 538                 return ((*fptr)());
 539 
 540         return (0);
 541 }
 542 
 543 /*
 544  * Mutex interfaces to resolve references from any objects extracted from
 545  * libc_pic.a.  Note, as ld.so.1 is essentially single threaded these can be
 546  * noops.
 547  */
 548 #pragma weak lmutex_lock = mutex_lock
 549 /* ARGSUSED */
 550 int
 551 mutex_lock(mutex_t *mp)
 552 {
 553         return (0);
 554 }
 555 
 556 #pragma weak lmutex_unlock = mutex_unlock
 557 /* ARGSUSED */
 558 int
 559 mutex_unlock(mutex_t *mp)
 560 {
 561         return (0);
 562 }
 563 
 564 /* ARGSUSED */
 565 int
 566 mutex_init(mutex_t *mp, int type, void *arg)
 567 {
 568         return (0);
 569 }
 570 
 571 /* ARGSUSED */
 572 int
 573 mutex_destroy(mutex_t *mp)
 574 {
 575         return (0);
 576 }
 577 
 578 /*
 579  * This is needed to satisfy sysconf() (case _SC_THREAD_STACK_MIN)
 580  */
 581 size_t
 582 thr_min_stack()
 583 {
 584         return (sizeof (uintptr_t) * 1024);
 585 }
 586 
 587 /*
 588  * Local str[n]casecmp() interfaces for the dynamic linker,
 589  * to avoid problems when linking with libc_pic.a
 590  */
 591 int
 592 strcasecmp(const char *s1, const char *s2)
 593 {
 594         extern int ascii_strcasecmp(const char *, const char *);
 595 
 596         return (ascii_strcasecmp(s1, s2));
 597 }
 598 
 599 int
 600 strncasecmp(const char *s1, const char *s2, size_t n)
 601 {
 602         extern int ascii_strncasecmp(const char *, const char *, size_t);
 603 
 604         return (ascii_strncasecmp(s1, s2, n));
 605 }
 606 
 607 /*
 608  * The following functions are cancellation points in libc.
 609  * They are called from other functions in libc that we extract
 610  * and use directly.  We don't do cancellation while we are in
 611  * the dynamic linker, so we redefine these to call the primitive,
 612  * non-cancellation interfaces.
 613  */
 614 int
 615 close(int fildes)
 616 {
 617         extern int __close(int);
 618 
 619         return (__close(fildes));
 620 }
 621 
 622 int
 623 fcntl(int fildes, int cmd, ...)
 624 {
 625         extern int __fcntl(int, int, ...);
 626         intptr_t arg;
 627         va_list ap;
 628 
 629         va_start(ap, cmd);
 630         arg = va_arg(ap, intptr_t);
 631         va_end(ap);
 632         return (__fcntl(fildes, cmd, arg));
 633 }
 634 
 635 int
 636 open(const char *path, int oflag, ...)
 637 {
 638         extern int __open(const char *, int, mode_t);
 639         mode_t mode;
 640         va_list ap;
 641 
 642         va_start(ap, oflag);
 643         mode = va_arg(ap, mode_t);
 644         va_end(ap);
 645         return (__open(path, oflag, mode));
 646 }
 647 
 648 int
 649 openat(int fd, const char *path, int oflag, ...)
 650 {
 651         extern int __openat(int, const char *, int, mode_t);
 652         mode_t mode;
 653         va_list ap;
 654 
 655         va_start(ap, oflag);
 656         mode = va_arg(ap, mode_t);
 657         va_end(ap);
 658         return (__openat(fd, path, oflag, mode));
 659 }
 660 
 661 ssize_t
 662 read(int fd, void *buf, size_t size)
 663 {
 664         extern ssize_t __read(int, void *, size_t);
 665         return (__read(fd, buf, size));
 666 }
 667 
 668 ssize_t
 669 write(int fd, const void *buf, size_t size)
 670 {
 671         extern ssize_t __write(int, const void *, size_t);
 672         return (__write(fd, buf, size));
 673 }
 674 
 675 /*
 676  * ASCII versions of ctype character classification functions.  This avoids
 677  * pulling in the entire locale framework that is in libc.
 678  */
 679 
 680 int
 681 isdigit(int c)
 682 {
 683         return ((c >= '0' && c <= '9') ? 1 : 0);
 684 }
 685 
 686 int
 687 isupper(int c)
 688 {
 689         return ((c >= 'A' && c <= 'Z') ? 1 : 0);
 690 }
 691 
 692 int
 693 islower(int c)
 694 {
 695         return ((c >= 'a' && c <= 'z') ? 1 : 0);
 696 }
 697 
 698 int
 699 isspace(int c)
 700 {
 701         return (((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n') ||
 702             (c == '\v') || (c == '\f')) ? 1 : 0);
 703 }
 704 
 705 int
 706 isxdigit(int c)
 707 {
 708         return ((isdigit(c) || (c >= 'A' && c <= 'F') ||
 709             (c >= 'a' && c <= 'f')) ? 1 : 0);
 710 }
 711 
 712 int
 713 isalpha(int c)
 714 {
 715         return ((isupper(c) || islower(c)) ? 1 : 0);
 716 }
 717 
 718 int
 719 isalnum(int c)
 720 {
 721         return ((isalpha(c) || isdigit(c)) ? 1 : 0);
 722 }
 723 
 724 #if defined(__i386) || defined(__amd64)
 725 /*
 726  * Instead of utilizing the comm page for clock_gettime, rtld uses the raw
 727  * syscall instead.  Doing so decreases the surface of symbols needed from libc
 728  * for a modest performance cost.
 729  */
 730 extern int __clock_gettime_sys(clockid_t, struct timespec *);
 731 
 732 int
 733 __clock_gettime(clockid_t clock_id, struct timespec *tp)
 734 {
 735         return (__clock_gettime_sys(clock_id, tp));
 736 }
 737 #endif /* defined(__i386) || defined(__amd64) */
 738 
 739 /*
 740  * In a similar vein to the is* functions above, we also have to define our own
 741  * version of strerror, as it is implemented in terms of the locale aware
 742  * strerror_l, and we'd rather not have the full set of libc symbols used here.
 743  */
 744 extern const char _sys_errs[];
 745 extern const int _sys_index[];
 746 extern int _sys_num_err;
 747 
 748 char *
 749 strerror(int errnum)
 750 {
 751         if (errnum < _sys_num_err && errnum >= 0) {
 752                 return (dgettext("SUNW_OST_OSLIB",
 753                     (char *)&_sys_errs[_sys_index[errnum]]));
 754         }
 755 
 756         errno = EINVAL;
 757         return (dgettext("SUNW_OST_OSLIB", "Unknown error"));
 758 }