4 * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * Some platform-dependent definitions to sync up the C support level.
28 * Some to a C99-ish level, some related utility code.
31 * + make "static inline" work
32 * + 64-bit types and load/store code
34 * + shared library init/fini hooks
35 * + consistent getpwnam/getpwuid interfaces
45 /* Initialization and finalization function support for libraries.
47 At top level, before the functions are defined or even declared:
48 MAKE_INIT_FUNCTION(init_fn);
49 MAKE_FINI_FUNCTION(fini_fn);
51 int init_fn(void) { ... }
52 void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
53 In code, in the same file:
54 err = CALL_INIT_FUNCTION(init_fn);
56 To trigger or verify the initializer invocation from another file,
57 a helper function must be created.
59 This model handles both the load-time execution (Windows) and
60 delayed execution (pthread_once) approaches, and should be able to
61 guarantee in both cases that the init function is run once, in one
62 thread, before other stuff in the library is done; furthermore, the
63 finalization code should only run if the initialization code did.
64 (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via
65 another function hidden in macros, but this is hairy enough
68 The init_fn and fini_fn names should be chosen such that any
69 exported names staring with those names, and optionally followed by
70 additional characters, fits in with any namespace constraints on
71 the library in question.
74 There's also PROGRAM_EXITING() currently always defined as zero.
75 If there's some trivial way to find out if the fini function is
76 being called because the program that the library is linked into is
77 exiting, we can just skip all the work because the resources are
78 about to be freed up anyways. Generally this is likely to be the
79 same as distinguishing whether the library was loaded dynamically
80 while the program was running, or loaded as part of program
81 startup. On most platforms, I don't think we can distinguish these
82 cases easily, and it's probably not worth expending any significant
83 effort. (Note in particular that atexit() won't do, because if the
84 library is explicitly loaded and unloaded, it would have to be able
85 to deregister the atexit callback function. Also, the system limit
86 on atexit callbacks may be small.)
89 Implementation outline:
91 Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
92 is sought at library build time, and code is added to invoke the
93 function when the library is unloaded. MAKE_INIT_FUNCTION does
94 likewise, but the function is invoked when the library is loaded,
95 and an extra variable is declared to hold an error code and a "yes
96 the initializer ran" flag. CALL_INIT_FUNCTION blows up if the flag
97 isn't set, otherwise returns the error code.
99 UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a
100 name derived from the function name, containing a k5_once_t
101 (pthread_once_t or int), an error code, and a pointer to the
102 function. The function itself is declared static, but the
103 associated variable has external linkage. CALL_INIT_FUNCTION
104 ensures thath the function is called exactly once (pthread_once or
105 just check the flag) and returns the stored error code (or the
108 (That's the basic idea. With some debugging assert() calls and
109 such, it's a bit more complicated. And we also need to handle
110 doing the pthread test at run time on systems where that works, so
111 we use the k5_once_t stuff instead.)
113 UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
114 function as a destructor, and the run time linker support or
115 whatever will cause it to be invoked when the library is unloaded,
116 the program ends, etc.
118 UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with
119 a magic name that is sought at library build time, and linker
120 options are used to mark it as a finalization function for the
121 library. The symbol must be exported.
123 UNIX, no library finalization support: The finalization function
124 never runs, and we leak memory. Tough.
126 DELAY_INITIALIZER will be defined by the configure script if we
127 want to use k5_once instead of load-time initialization. That'll
128 be the preferred method on most systems except Windows, where we
129 have to initialize some mutexes.
134 For maximum flexibility in defining the macros, the function name
135 parameter should be a simple name, not even a macro defined as
136 another name. The function should have a unique name, and should
137 conform to whatever namespace is used by the library in question.
138 (We do have export lists, but (1) they're not used for all
139 platforms, and (2) they're not used for static libraries.)
141 If the macro expansion needs the function to have been declared, it
142 must include a declaration. If it is not necessary for the symbol
143 name to be exported from the object file, the macro should declare
144 it as "static". Hence the signature must exactly match "void
145 foo(void)". (ANSI C allows a static declaration followed by a
146 non-static one; the result is internal linkage.) The macro
147 expansion has to come before the function, because gcc apparently
148 won't act on "__attribute__((constructor))" if it comes after the
151 This is going to be compiler- and environment-specific, and may
152 require some support at library build time, and/or "asm"
153 statements. But through macro expansion and auxiliary functions,
154 we should be able to handle most things except #pragma.
156 It's okay for this code to require that the library be built
157 with the same compiler and compiler options throughout, but
158 we shouldn't require that the library and application use the
161 For static libraries, we don't really care about cleanup too much,
162 since it's all memory handling and mutex allocation which will all
163 be cleaned up when the program exits. Thus, it's okay if gcc-built
164 static libraries don't play nicely with cc-built executables when
165 it comes to static constructors, just as long as it doesn't cause
168 For dynamic libraries on UNIX, we'll use pthread_once-type support
169 to do delayed initialization, so if finalization can't be made to
170 work, we'll only have memory leaks in a load/use/unload cycle. If
171 anyone (like, say, the OS vendor) complains about this, they can
172 tell us how to get a shared library finalization function invoked
175 Currently there's --disable-delayed-initialization for preventing
176 the initialization from being delayed on UNIX, but that's mainly
177 just for testing the linker options for initialization, and will
178 probably be removed at some point. */
182 # define JOIN__2_2(A,B) A ## _ ## _ ## B
183 # define JOIN__2(A,B) JOIN__2_2(A,B)
185 /* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set,
186 always provide a function by the expected name, even if we're
187 delaying initialization. */
189 #if defined(DELAY_INITIALIZER)
191 /* Run the initialization code during program execution, at the latest
192 possible moment. This means multiple threads may be active. */
193 # include "k5-thread.h"
194 typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
195 # ifdef USE_LINKER_INIT_OPTION
196 # define MAYBE_DUMMY_INIT(NAME) \
197 void JOIN__2(NAME, auxinit) () { }
199 # define MAYBE_DUMMY_INIT(NAME)
202 /* Do it in macro form so we get the file/line of the invocation if
203 the assertion fails. */
204 # define k5_call_init_function(I) \
206 k5_init_t *k5int_i = (I); \
207 int k5int_err = k5_once(&k5int_i->once, k5int_i->fn); \
210 : (assert(k5int_i->did_run != 0), k5int_i->error)); \
212 # define MAYBE_DEFINE_CALLINIT_FUNCTION
214 # define MAYBE_DEFINE_CALLINIT_FUNCTION \
215 static inline int k5_call_init_function(k5_init_t *i) \
218 err = k5_once(&i->once, i->fn); \
221 assert (i->did_run != 0); \
225 # define MAKE_INIT_FUNCTION(NAME) \
226 static int NAME(void); \
227 MAYBE_DUMMY_INIT(NAME) \
228 /* forward declaration for use in initializer */ \
229 static void JOIN__2(NAME, aux) (void); \
230 static k5_init_t JOIN__2(NAME, once) = \
231 { K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) }; \
232 MAYBE_DEFINE_CALLINIT_FUNCTION \
233 static void JOIN__2(NAME, aux) (void) \
235 JOIN__2(NAME, once).did_run = 1; \
236 JOIN__2(NAME, once).error = NAME(); \
238 /* so ';' following macro use won't get error */ \
239 static int NAME(void)
240 # define CALL_INIT_FUNCTION(NAME) \
241 k5_call_init_function(& JOIN__2(NAME, once))
242 /* This should be called in finalization only, so we shouldn't have
243 multiple active threads mucking around in our library at this
244 point. So ignore the once_t object and just look at the flag.
246 XXX Could we have problems with memory coherence between processors
247 if we don't invoke mutex/once routines? Probably not, the
248 application code should already be coordinating things such that
249 the library code is not in use by this point, and memory
250 synchronization will be needed there. */
251 # define INITIALIZER_RAN(NAME) \
252 (JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
254 # define PROGRAM_EXITING() (0)
256 #elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
258 /* Run initializer at load time, via GCC/C++ hook magic. */
260 # ifdef USE_LINKER_INIT_OPTION
261 /* Both gcc and linker option?? Favor gcc. */
262 # define MAYBE_DUMMY_INIT(NAME) \
263 void JOIN__2(NAME, auxinit) () { }
265 # define MAYBE_DUMMY_INIT(NAME)
268 typedef struct { int error; unsigned char did_run; } k5_init_t;
269 # define MAKE_INIT_FUNCTION(NAME) \
270 MAYBE_DUMMY_INIT(NAME) \
271 static k5_init_t JOIN__2(NAME, ran) \
273 static void JOIN__2(NAME, aux)(void) \
274 __attribute__((constructor)); \
275 static int NAME(void); \
276 static void JOIN__2(NAME, aux)(void) \
278 JOIN__2(NAME, ran).error = NAME(); \
279 JOIN__2(NAME, ran).did_run = 3; \
281 static int NAME(void)
282 # define CALL_INIT_FUNCTION(NAME) \
283 (JOIN__2(NAME, ran).did_run == 3 \
284 ? JOIN__2(NAME, ran).error \
286 # define INITIALIZER_RAN(NAME) (JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0)
288 # define PROGRAM_EXITING() (0)
290 #elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32)
292 /* Run initializer at load time, via linker magic, or in the
293 case of WIN32, win_glue.c hard-coded knowledge. */
294 typedef struct { int error; unsigned char did_run; } k5_init_t;
295 # define MAKE_INIT_FUNCTION(NAME) \
296 static k5_init_t JOIN__2(NAME, ran) \
298 static int NAME(void); \
299 void JOIN__2(NAME, auxinit)() \
301 JOIN__2(NAME, ran).error = NAME(); \
302 JOIN__2(NAME, ran).did_run = 3; \
304 static int NAME(void)
305 # define CALL_INIT_FUNCTION(NAME) \
306 (JOIN__2(NAME, ran).did_run == 3 \
307 ? JOIN__2(NAME, ran).error \
309 # define INITIALIZER_RAN(NAME) \
310 (JOIN__2(NAME, ran).error == 0)
312 # define PROGRAM_EXITING() (0)
316 # error "Don't know how to do load-time initializers for this configuration."
318 # define PROGRAM_EXITING() (0)
324 #if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32)
325 /* If we're told the linker option will be used, it doesn't really
326 matter what compiler we're using. Do it the same way
331 /* On HP-UX, we need this auxiliary function. At dynamic load or
332 unload time (but *not* program startup and termination for
333 link-time specified libraries), the linker-indicated function
334 is called with a handle on the library and a flag indicating
335 whether it's being loaded or unloaded.
337 The "real" fini function doesn't need to be exported, so
340 As usual, the final declaration is just for syntactic
341 convenience, so the top-level invocation of this macro can be
342 followed by a semicolon. */
345 # define MAKE_FINI_FUNCTION(NAME) \
346 static void NAME(void); \
347 void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \
348 void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); } \
349 static void NAME(void)
351 # else /* not hpux */
353 # define MAKE_FINI_FUNCTION(NAME) \
358 #elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
359 /* If we're using gcc, if the C++ support works, the compiler should
360 build executables and shared libraries that support the use of
361 static constructors and destructors. The C compiler supports a
362 function attribute that makes use of the same facility as C++.
364 XXX How do we know if the C++ support actually works? */
365 # define MAKE_FINI_FUNCTION(NAME) \
366 static void NAME(void) __attribute__((destructor))
368 #elif !defined(SHARED)
370 /* In this case, we just don't care about finalization.
372 The code will still define the function, but we won't do anything
373 with it. Annoying: This may generate unused-function warnings. */
375 # define MAKE_FINI_FUNCTION(NAME) \
376 static void NAME(void)
380 # error "Don't know how to do unload-time finalization for this configuration."
385 /* 64-bit support: krb5_ui_8 and krb5_int64.
387 This should move to krb5.h eventually, but without the namespace
388 pollution from the autoconf macros. */
389 #if defined(HAVE_STDINT_H) || defined(HAVE_INTTYPES_H)
390 # ifdef HAVE_STDINT_H
393 # ifdef HAVE_INTTYPES_H
394 # include <inttypes.h>
396 # define INT64_TYPE int64_t
397 # define UINT64_TYPE uint64_t
398 #elif defined(_WIN32)
399 # define INT64_TYPE signed __int64
400 # define UINT64_TYPE unsigned __int64
401 #else /* not Windows, and neither stdint.h nor inttypes.h */
402 # define INT64_TYPE signed long long
403 # define UINT64_TYPE unsigned long long
408 # define SIZE_MAX ((size_t)((size_t)0 - 1))
411 /* Read and write integer values as (unaligned) octet strings in
412 specific byte orders. Add per-platform optimizations as
417 #elif HAVE_MACHINE_ENDIAN_H
418 # include <machine/endian.h>
420 /* Check for BIG/LITTLE_ENDIAN macros. If exactly one is defined, use
421 it. If both are defined, then BYTE_ORDER should be defined and
422 match one of them. Try those symbols, then try again with an
423 underscore prefix. */
424 #if defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
425 # if BYTE_ORDER == BIG_ENDIAN
428 # if BYTE_ORDER == LITTLE_ENDIAN
431 #elif defined(BIG_ENDIAN)
433 #elif defined(LITTLE_ENDIAN)
435 #elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
436 # if _BYTE_ORDER == _BIG_ENDIAN
439 # if _BYTE_ORDER == _LITTLE_ENDIAN
442 #elif defined(_BIG_ENDIAN)
444 #elif defined(_LITTLE_ENDIAN)
447 #if !defined(K5_BE) && !defined(K5_LE)
448 /* Look for some architectures we know about.
450 MIPS can use either byte order, but the preprocessor tells us which
451 mode we're compiling for. The GCC config files indicate that
452 variants of Alpha and IA64 might be out there with both byte
453 orders, but until we encounter the "wrong" ones in the real world,
454 just go with the default (unless there are cpp predefines to help
457 As far as I know, only PDP11 and ARM (which we don't handle here)
458 have strange byte orders where an 8-byte value isn't laid out as
459 either 12345678 or 87654321. */
460 # if defined(__i386__) || defined(_MIPSEL) || defined(__alpha__) || defined(__ia64__)
463 # if defined(__hppa__) || defined(__rs6000__) || defined(__sparc__) || defined(_MIPSEB) || defined(__m68k__) || defined(__sparc64__) || defined(__ppc__) || defined(__ppc64__)
467 #if defined(K5_BE) && defined(K5_LE)
468 # error "oops, check the byte order macros"
471 /* Optimize for GCC on platforms with known byte orders.
473 GCC's packed structures can be written to with any alignment; the
474 compiler will use byte operations, unaligned-word operations, or
475 normal memory ops as appropriate for the architecture.
477 This assumes the availability of uint##_t types, which should work
478 on most of our platforms except Windows, where we're not using
481 # define PUT(SIZE,PTR,VAL) (((struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i = (VAL))
482 # define GET(SIZE,PTR) (((const struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i)
483 # define PUTSWAPPED(SIZE,PTR,VAL) PUT(SIZE,PTR,SWAP##SIZE(VAL))
484 # define GETSWAPPED(SIZE,PTR) SWAP##SIZE(GET(SIZE,PTR))
486 /* To do: Define SWAP16, SWAP32, SWAP64 macros to byte-swap values
487 with the indicated numbers of bits.
489 Linux: byteswap.h, bswap_16 etc.
491 Mac OS X: machine/endian.h or byte_order.h, NXSwap{Short,Int,LongLong}
492 NetBSD: sys/bswap.h, bswap16 etc. */
494 #if defined(HAVE_BYTESWAP_H) && defined(HAVE_BSWAP_16)
495 # include <byteswap.h>
496 # define SWAP16 bswap_16
497 # define SWAP32 bswap_32
498 # ifdef HAVE_BSWAP_64
499 # define SWAP64 bswap_64
504 store_16_be (unsigned int val, unsigned char *p)
506 #if defined(__GNUC__) && defined(K5_BE)
508 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
509 PUTSWAPPED(16,p,val);
511 p[0] = (val >> 8) & 0xff;
512 p[1] = (val ) & 0xff;
516 store_32_be (unsigned int val, unsigned char *p)
518 #if defined(__GNUC__) && defined(K5_BE)
520 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
521 PUTSWAPPED(32,p,val);
523 p[0] = (val >> 24) & 0xff;
524 p[1] = (val >> 16) & 0xff;
525 p[2] = (val >> 8) & 0xff;
526 p[3] = (val ) & 0xff;
530 store_64_be (UINT64_TYPE val, unsigned char *p)
532 #if defined(__GNUC__) && defined(K5_BE)
534 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
535 PUTSWAPPED(64,p,val);
537 p[0] = (unsigned char)((val >> 56) & 0xff);
538 p[1] = (unsigned char)((val >> 48) & 0xff);
539 p[2] = (unsigned char)((val >> 40) & 0xff);
540 p[3] = (unsigned char)((val >> 32) & 0xff);
541 p[4] = (unsigned char)((val >> 24) & 0xff);
542 p[5] = (unsigned char)((val >> 16) & 0xff);
543 p[6] = (unsigned char)((val >> 8) & 0xff);
544 p[7] = (unsigned char)((val ) & 0xff);
547 static inline unsigned short
548 load_16_be (const unsigned char *p)
550 #if defined(__GNUC__) && defined(K5_BE)
552 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
553 return GETSWAPPED(16,p);
555 return (p[1] | (p[0] << 8));
558 static inline unsigned int
559 load_32_be (const unsigned char *p)
561 #if defined(__GNUC__) && defined(K5_BE)
563 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
564 return GETSWAPPED(32,p);
566 return (p[3] | (p[2] << 8)
567 | ((uint32_t) p[1] << 16)
568 | ((uint32_t) p[0] << 24));
571 static inline UINT64_TYPE
572 load_64_be (const unsigned char *p)
574 #if defined(__GNUC__) && defined(K5_BE)
576 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
577 return GETSWAPPED(64,p);
579 return ((UINT64_TYPE)load_32_be(p) << 32) | load_32_be(p+4);
583 store_16_le (unsigned int val, unsigned char *p)
585 #if defined(__GNUC__) && defined(K5_LE)
587 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
588 PUTSWAPPED(16,p,val);
590 p[1] = (val >> 8) & 0xff;
591 p[0] = (val ) & 0xff;
595 store_32_le (unsigned int val, unsigned char *p)
597 #if defined(__GNUC__) && defined(K5_LE)
599 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
600 PUTSWAPPED(32,p,val);
602 p[3] = (val >> 24) & 0xff;
603 p[2] = (val >> 16) & 0xff;
604 p[1] = (val >> 8) & 0xff;
605 p[0] = (val ) & 0xff;
609 store_64_le (UINT64_TYPE val, unsigned char *p)
611 #if defined(__GNUC__) && defined(K5_LE)
613 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
614 PUTSWAPPED(64,p,val);
616 p[7] = (unsigned char)((val >> 56) & 0xff);
617 p[6] = (unsigned char)((val >> 48) & 0xff);
618 p[5] = (unsigned char)((val >> 40) & 0xff);
619 p[4] = (unsigned char)((val >> 32) & 0xff);
620 p[3] = (unsigned char)((val >> 24) & 0xff);
621 p[2] = (unsigned char)((val >> 16) & 0xff);
622 p[1] = (unsigned char)((val >> 8) & 0xff);
623 p[0] = (unsigned char)((val ) & 0xff);
626 static inline unsigned short
627 load_16_le (const unsigned char *p)
629 #if defined(__GNUC__) && defined(K5_LE)
631 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
632 return GETSWAPPED(16,p);
634 return (p[0] | (p[1] << 8));
637 static inline unsigned int
638 load_32_le (const unsigned char *p)
640 #if defined(__GNUC__) && defined(K5_LE)
642 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
643 return GETSWAPPED(32,p);
645 return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
648 static inline UINT64_TYPE
649 load_64_le (const unsigned char *p)
651 #if defined(__GNUC__) && defined(K5_LE)
653 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
654 return GETSWAPPED(64,p);
656 return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
660 static inline unsigned short
661 load_16_n (const unsigned char *p)
671 static inline unsigned int
672 load_32_n (const unsigned char *p)
682 static inline UINT64_TYPE
683 load_64_n (const unsigned char *p)
690 /* Make the interfaces to getpwnam and getpwuid consistent.
691 Model the wrappers on the POSIX thread-safe versions, but
692 use the unsafe system versions if the safe ones don't exist
693 or we can't figure out their interfaces. */
695 /* int k5_getpwnam_r(const char *, blah blah) */
696 #ifdef HAVE_GETPWNAM_R
697 # ifndef GETPWNAM_R_4_ARGS
699 # define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
700 (getpwnam_r(NAME,REC,BUF,BUFSIZE,OUT) == 0 \
701 ? (*(OUT) == NULL ? -1 : 0) : -1)
704 # ifdef GETPWNAM_R_RETURNS_INT
705 # define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
706 (getpwnam_r(NAME,REC,BUF,BUFSIZE) == 0 \
707 ? (*(OUT) = REC, 0) \
708 : (*(OUT) = NULL, -1))
710 # define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
711 (*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
714 #else /* no getpwnam_r, or can't figure out #args or return type */
715 /* Will get warnings about unused variables. */
716 # define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
717 (*(OUT) = getpwnam(NAME), *(OUT) == NULL ? -1 : 0)
720 /* int k5_getpwuid_r(uid_t, blah blah) */
721 #ifdef HAVE_GETPWUID_R
722 # ifndef GETPWUID_R_4_ARGS
724 # define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
725 (getpwuid_r(UID,REC,BUF,BUFSIZE,OUT) == 0 \
726 ? (*(OUT) == NULL ? -1 : 0) : -1)
728 /* POSIX drafts? Yes, I mean to test GETPWNAM... here. Less junk to
729 do at configure time. */
730 # ifdef GETPWNAM_R_RETURNS_INT
731 # define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
732 (getpwuid_r(UID,REC,BUF,BUFSIZE) == 0 \
733 ? (*(OUT) = REC, 0) \
734 : (*(OUT) = NULL, -1))
736 # define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
737 (*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
740 #else /* no getpwuid_r, or can't figure out #args or return type */
741 /* Will get warnings about unused variables. */
742 # define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
743 (*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
747 #endif /* K5_PLATFORM_H */