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