+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <printerdb.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <netinet/if_ether.h>
+#include <libkern/OSAtomic.h>
+#include "si_module.h"
+#include "libinfo.h"
+#include <thread_data.h>
+#include <sys/kauth.h>
+#include "netdb_async.h"
+
+#define SOCK_UNSPEC 0
+#define IPPROTO_UNSPEC 0
+#define IPV6_ADDR_LEN 16
+#define IPV4_ADDR_LEN 4
+
+/* SPI from long ago */
+int _proto_stayopen;
+
+__private_extern__ struct addrinfo *si_list_to_addrinfo(si_list_t *list);
+
+/*
+ * Impedence matching for async calls.
+ *
+ * This layer holds on to the caller's callback and context in this
+ * structure, which gets passed to the si_module async routines along
+ * with a callbac in this layer. When this layer gets a callback,
+ * it can save the item or list in thread-specific memory and then
+ * invoke the caller's callback with the appropriate data type.
+ */
+
+typedef struct
+{
+ void *orig_callback;
+ void *orig_context;
+ uint32_t cat;
+ int32_t key_offset;
+} si_context_t;
+
+__private_extern__ si_mod_t *
+si_search(void)
+{
+ static si_mod_t *search = NULL;
+ static OSSpinLock spin = OS_SPINLOCK_INIT;
+
+ if (search == NULL)
+ {
+ OSSpinLockLock(&spin);
+ if (search == NULL) search = si_module_with_name("search");
+ OSSpinLockUnlock(&spin);
+ }
+
+ return search;
+}
+
+static void
+si_libinfo_general_callback(si_item_t *item, uint32_t status, void *ctx)
+{
+ si_context_t *sictx;
+ union
+ {
+ char *x;
+ struct passwd *u;
+ struct group *g;
+ struct grouplist_s *l;
+ struct hostent *h;
+ struct netent *n;
+ struct servent *s;
+ struct protoent *p;
+ struct rpcent *r;
+ struct fstab *f;
+ } res;
+
+ if (ctx == NULL) return;
+
+ sictx = (si_context_t *)ctx;
+
+ if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
+ {
+ free(sictx);
+ si_item_release(item);
+ return;
+ }
+
+ if (sictx->key_offset >= 0)
+ {
+ LI_set_thread_item(sictx->cat + sictx->key_offset, item);
+ }
+
+ res.x = NULL;
+ if (item != NULL) res.x = (char*)((uintptr_t)item + sizeof(si_item_t));
+
+ switch (sictx->cat)
+ {
+ case CATEGORY_USER:
+ {
+ ((si_user_async_callback)(sictx->orig_callback))(res.u, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_GROUP:
+ {
+ ((si_group_async_callback)(sictx->orig_callback))(res.g, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_GROUPLIST:
+ {
+ ((si_grouplist_async_callback)(sictx->orig_callback))(res.l, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_HOST_IPV4:
+ case CATEGORY_HOST_IPV6:
+ {
+ ((si_host_async_callback)(sictx->orig_callback))(res.h, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_NETWORK:
+ {
+ ((si_network_async_callback)(sictx->orig_callback))(res.n, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_SERVICE:
+ {
+ ((si_service_async_callback)(sictx->orig_callback))(res.s, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_PROTOCOL:
+ {
+ ((si_protocol_async_callback)(sictx->orig_callback))(res.p, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_RPC:
+ {
+ ((si_rpc_async_callback)(sictx->orig_callback))(res.r, sictx->orig_context);
+ break;
+ }
+ case CATEGORY_FS:
+ {
+ ((si_fs_async_callback)(sictx->orig_callback))(res.f, sictx->orig_context);
+ break;
+ }
+ }
+
+ free(sictx);
+}
+
+/* USER */
+
+struct passwd *
+getpwnam(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_user_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_USER + 100, item);
+
+ if (item == NULL) return NULL;
+ return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getpwnam_async_call(const char *name, si_user_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_USER;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_USER_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getpwnam_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d\n", __func__, uid);
+#endif
+
+ item = si_user_byuid(si_search(), uid);
+ LI_set_thread_item(CATEGORY_USER + 200, item);
+
+ if (item == NULL) return NULL;
+ return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getpwuid_async_call(uid_t uid, si_user_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %d\n", __func__, uid);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_USER;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_USER_BYUID, NULL, NULL, (uint32_t)uid, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getpwuid_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setpwent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_USER, NULL);
+}
+
+struct passwd *
+getpwent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_USER);
+ if (list == NULL)
+ {
+ list = si_user_all(si_search());
+ LI_set_thread_list(CATEGORY_USER, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endpwent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_USER, NULL);
+}
+
+int
+setpassent(int ignored)
+{
+ si_list_t *list;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_USER);
+ si_list_reset(list);
+
+ if (list == NULL) return 0;
+ return 1;
+}
+
+/* GROUP */
+
+struct group *
+getgrnam(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_group_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_GROUP + 100, item);
+
+ if (item == NULL) return NULL;
+ return (struct group *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getgrnam_async_call(const char *name, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_GROUP;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_GROUP_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getgrnam_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct group *
+getgrgid(gid_t gid)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d\n", __func__, gid);
+#endif
+
+ item = si_group_bygid(si_search(), gid);
+ LI_set_thread_item(CATEGORY_GROUP + 200, item);
+
+ if (item == NULL) return NULL;
+ return (struct group *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getgrgid_async_call(gid_t gid, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %d\n", __func__, gid);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_GROUP;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_GROUP_BYGID, NULL, NULL, (uint32_t)gid, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getgruid_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setgrent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_GROUP, NULL);
+}
+
+struct group *
+getgrent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_GROUP);
+ if (list == NULL)
+ {
+ list = si_group_all(si_search());
+ LI_set_thread_list(CATEGORY_GROUP, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct group *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endgrent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_GROUP, NULL);
+}
+
+int
+setgroupent(int ignored)
+{
+ si_list_t *list;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_GROUP);
+ si_list_reset(list);
+
+ if (list == NULL) return 0;
+ return 1;
+}
+
+/* NETGROUP */
+int
+innetgr(const char *group, const char *host, const char *user, const char *domain)
+{
+ int res;
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %s %s %s\n", __func__, group, host, user, domain);
+#endif
+
+ res = si_in_netgroup(si_search(), group, host, user, domain);
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<- %s %d\n", __func__, res);
+#endif
+
+ return res;
+}
+
+/* N.B. there is no async innetgr */
+
+/*
+ * setnetgrent is really more like a getXXXbyname routine than a
+ * setXXXent routine, since we are looking up a netgroup by name.
+ */
+void
+setnetgrent(const char *name)
+{
+ si_list_t *list;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ list = si_netgroup_byname(si_search(), name);
+ LI_set_thread_list(CATEGORY_NETGROUP, list);
+}
+
+/* N.B. there is no async getnetgrent */
+
+int
+getnetgrent(char **host, char **user, char **domain)
+{
+ si_list_t *list;
+ si_item_t *item;
+ struct netgrent_s *ng;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_NETGROUP);
+ item = si_list_next(list);
+ if (item == NULL) return 0;
+
+ ng = (struct netgrent_s *)((uintptr_t)item + sizeof(si_item_t));
+
+ *host = ng->ng_host;
+ *user = ng->ng_user;
+ *domain = ng->ng_domain;
+
+ return 1;
+}
+
+void
+endnetgrent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_NETGROUP, NULL);
+}
+
+/* GROUPLIST */
+
+int
+getgrouplist(const char *name, int basegid, int *groups, int *ngroups)
+{
+ int i, j, x, g, add, max;
+ si_item_t *item;
+ si_grouplist_t *gl;
+
+ /*
+ * On input, ngroups specifies the size of the groups array.
+ * On output, it is set to the number of groups that are being returned.
+ * Returns -1 if the size is too small to fit all the groups that were found.
+ */
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
+#endif
+
+ if (name == NULL) return 0;
+ if (groups == NULL) return 0;
+ if (ngroups == NULL) return 0;
+
+ max = *ngroups;
+ *ngroups = 0;
+ if (max <= 0) return 0;
+
+ groups[0] = basegid;
+ *ngroups = 1;
+
+ item = si_grouplist(si_search(), name);
+ LI_set_thread_item(CATEGORY_GROUPLIST, item);
+ if (item == NULL) return 0;
+
+ gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ x = 1;
+
+ if (gl->gl_basegid != basegid)
+ {
+ if (x >= max) return -1;
+ groups[x] = gl->gl_basegid;
+ x++;
+ *ngroups = x;
+ }
+
+ for (i = 0; i < gl->gl_count; i++)
+ {
+ g = (int)*(gl->gl_gid[i]);
+ add = 1;
+ for (j = 0; (j < x) && (add == 1); j++) if (groups[j] == g) add = 0;
+ if (add == 0) continue;
+
+ if (x >= max) return -1;
+ groups[x] = g;
+ x++;
+ *ngroups = x;
+ }
+
+ return 0;
+}
+
+/* XXX to do: async getgrouplist */
+
+static int
+merge_gid(gid_t **list, gid_t g, int32_t *count)
+{
+ int i;
+
+ if (list == NULL) return -1;
+
+ if (*count == 0)
+ {
+ *list = (gid_t *)calloc(1, sizeof(gid_t));
+ if (list == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ (*list)[(*count)++] = g;
+ return 0;
+ }
+
+ for (i = 0; i < *count; i++) if ((*list)[i] == g) return 0;
+
+ *list = (gid_t *)reallocf(*list, (*count + 1) * sizeof(gid_t));
+ (*list)[(*count)++] = g;
+ return 0;
+}
+
+int32_t
+getgrouplist_2(const char *name, gid_t basegid, gid_t **groups)
+{
+ int32_t i, status, count;
+ gid_t g;
+ si_item_t *item;
+ si_grouplist_t *gl;
+
+ /*
+ * Passes back a gid_t list containing all the users groups (and basegid).
+ * Caller must free the list.
+ * Returns the number of gids in the list or -1 on failure.
+ */
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
+#endif
+
+ if (name == NULL) return 0;
+ if (groups == NULL) return 0;
+
+ item = si_grouplist(si_search(), name);
+ LI_set_thread_item(CATEGORY_GROUPLIST, item);
+ if (item == NULL) return -1;
+
+ gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ count = 0;
+ *groups = NULL;
+
+ status = merge_gid(groups, basegid, &count);
+ if (status != 0) return status;
+
+ status = merge_gid(groups, gl->gl_basegid, &count);
+ if (status != 0) return status;
+
+ for (i = 0; i < gl->gl_count; i++)
+ {
+ g = (gid_t)*(gl->gl_gid[i]);
+ status = merge_gid(groups, g, &count);
+ if (status != 0) return status;
+ }
+
+ return count;
+}
+
+int32_t
+getgroupcount(const char *name, gid_t basegid)
+{
+ int32_t i, status, count;
+ gid_t g;
+ si_item_t *item;
+ si_grouplist_t *gl;
+ gid_t *groups;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
+#endif
+
+ if (name == NULL) return 0;
+
+ item = si_grouplist(si_search(), name);
+ LI_set_thread_item(CATEGORY_GROUPLIST, item);
+ if (item == NULL) return -1;
+
+ gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ count = 0;
+ groups = NULL;
+
+ status = merge_gid(&groups, basegid, &count);
+ if (status != 0) return status;
+
+ status = merge_gid(&groups, gl->gl_basegid, &count);
+ if (status != 0) return status;
+
+ for (i = 0; i < gl->gl_count; i++)
+ {
+ g = (gid_t)*(gl->gl_gid[i]);
+ status = merge_gid(&groups, g, &count);
+ if (status != 0) return status;
+ }
+
+ if (groups != NULL) free(groups);
+
+ return count;
+}
+
+/* XXX to do: async getgrouplist_2 */
+
+int
+initgroups(const char *name, int basegid)
+{
+ int status, ngroups, groups[NGROUPS];
+ uid_t uid;
+#ifdef DS_AVAILABLE
+ si_item_t *item;
+ struct passwd *p;
+#endif
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
+#endif
+
+ /* KAUTH_UID_NONE tells the kernel not to fetch supplementary groups from DirectoryService */
+ uid = KAUTH_UID_NONE;
+
+#ifdef DS_AVAILABLE
+ /* get the UID for this user */
+ item = si_user_byname(si_search(), name);
+ if (item != NULL)
+ {
+ p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+ uid = p->pw_uid;
+
+ si_item_release(item);
+ }
+#endif
+
+ ngroups = NGROUPS;
+
+ status = getgrouplist(name, basegid, groups, &ngroups);
+ /*
+ * Ignore status.
+ * A failure either means that user belongs to more than NGROUPS groups
+ * or no groups at all.
+ */
+
+ status = syscall(SYS_initgroups, ngroups, groups, uid);
+ if (status < 0) return -1;
+
+ return 0;
+}
+
+/* ALIAS */
+
+struct aliasent *
+alias_getbyname(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_alias_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_ALIAS + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct aliasent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+alias_getbyname_async_call(const char *name, si_alias_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_ALIAS;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_ALIAS_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+alias_getbyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+alias_setent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_ALIAS, NULL);
+}
+
+struct aliasent *
+alias_getent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_ALIAS);
+ if (list == NULL)
+ {
+ list = si_alias_all(si_search());
+ LI_set_thread_list(CATEGORY_ALIAS, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct aliasent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+alias_endent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_ALIAS, NULL);
+}
+
+/* HOST */
+
+void
+freehostent(struct hostent *h)
+{
+ if (h == NULL) return;
+
+ si_item_t *item = (si_item_t *)((uintptr_t)h - sizeof(si_item_t));
+ si_item_release(item);
+}
+
+struct hostent *
+gethostbynameerrno(const char *name, int *err)
+{
+ si_item_t *item;
+ uint32_t status;
+ struct in_addr addr4;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ status = SI_STATUS_NO_ERROR;
+ item = NULL;
+
+ if (inet_aton(name, &addr4) == 1) item = si_ipnode_byname(si_search(), name, AF_INET, 0, &status);
+ else item = si_host_byname(si_search(), name, AF_INET, &status);
+
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+ if (err != NULL) *err = status;
+
+ LI_set_thread_item(CATEGORY_HOST + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ si_item_t *item;
+ uint32_t status;
+ struct in_addr addr4;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ status = SI_STATUS_NO_ERROR;
+ item = NULL;
+
+ if (inet_aton(name, &addr4) == 1) item = si_ipnode_byname(si_search(), name, AF_INET, 0, &status);
+ else item = si_host_byname(si_search(), name, AF_INET, &status);
+
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+ h_errno = status;
+
+ LI_set_thread_item(CATEGORY_HOST + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+gethostbyname_async_call(const char *name, si_host_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_HOST;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_HOST_BYNAME, name, NULL, AF_INET, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+mach_port_t
+gethostbyname_async_start(const char *name, si_host_async_callback callback, void *context)
+{
+ return gethostbyname_async_call(name, callback, context);
+}
+
+void
+gethostbyname_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+#if 0
+void
+gethostbyname_async_handle_reply(void *param)
+{
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+}
+#endif
+
+void
+gethostbyname_async_handleReply(void *param)
+{
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+ si_item_t *item;
+ uint32_t status;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+ si_mod_t *search = si_search();
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d\n", __func__, name, af);
+#endif
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ status = SI_STATUS_NO_ERROR;
+ item = NULL;
+
+ if (((af == AF_INET) && (inet_aton(name, &addr4) == 1)) || ((af == AF_INET6) && (inet_pton(af, name, &addr6) == 1)))
+ {
+ item = si_ipnode_byname(search, name, (uint32_t)af, 0, &status);
+ }
+ else
+ {
+ item = si_host_byname(search, name, (uint32_t)af, &status);
+ }
+
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+ h_errno = status;
+
+ LI_set_thread_item(CATEGORY_HOST + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+gethostbyname2_async_call(const char *name, int af, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s %d\n", __func__, name, af);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_HOST;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_HOST_BYNAME, name, NULL, (uint32_t)af, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+gethostbyname2_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+void
+gethostbyname2_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int type)
+{
+ si_item_t *item;
+ uint32_t status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, (type == AF_INET) ? inet_ntoa(*(struct in_addr *)addr) : "-IPv6-");
+#endif
+
+ status = SI_STATUS_NO_ERROR;
+
+ item = si_host_byaddr(si_search(), addr, (uint32_t)type, &status);
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+ h_errno = status;
+
+ LI_set_thread_item(CATEGORY_HOST + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+gethostbyaddr_async_call(const void *addr, socklen_t len, int type, si_host_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+ uint32_t addrlen;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, (type == AF_INET) ? inet_ntoa(*(struct in_addr *)addr) : "-IPv6-");
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_HOST;
+ sictx->key_offset = 200;
+
+ /* addr is not a C string - pass length in num3 */
+ addrlen = len;
+ return si_async_call(si_search(), SI_CALL_HOST_BYADDR, addr, NULL, (uint32_t)type, 0, addrlen, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+mach_port_t
+gethostbyaddr_async_start(const char *addr, int len, int family, si_host_async_callback callback, void *context)
+{
+ socklen_t slen = len;
+
+ return gethostbyaddr_async_call(addr, slen, family, callback, context);
+}
+
+void
+gethostbyaddr_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+#if 0
+void
+gethostbyaddr_async_handle_reply(void *param)
+{
+
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+}
+#endif
+
+void
+gethostbyaddr_async_handleReply(void *param)
+{
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+}
+
+struct hostent *
+getipnodebyname(const char *name, int family, int flags, int *err)
+{
+ si_item_t *item;
+ uint32_t status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %d 0x%08x\n", __func__, name, family, flags);
+#endif
+
+ status = SI_STATUS_NO_ERROR;
+
+ item = si_ipnode_byname(si_search(), name, family, flags, &status);
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+ if (err != NULL) *err = status;
+
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+#if 0
+mach_port_t
+getipnodebyname_async_call(const char *name, int family, int flags, int *err, si_host_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s %d 0x%08x\n", __func__, name, family, flags);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_HOST;
+ sictx->key_offset = -1;
+
+ return si_async_call(si_search(), SI_CALL_IPNODE_BYNAME, name, NULL, (uint32_t)family, (uint32_t)flags, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+mach_port_t
+getipnodebyname_async_start(const char *name, int family, int flags, int *err, si_host_async_callback callback, void *context)
+{
+ return getipnodebyname_async_call(name, family, flags, err, callback, context);
+}
+
+void
+getipnodebyname_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+void
+getipnodebyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+getipnodebyname_async_handleReply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+#endif
+
+static int
+is_a4_mapped(const char *s)
+{
+ int i;
+ u_int8_t c;
+
+ if (s == NULL) return 0;
+
+ for (i = 0; i < 10; i++)
+ {
+ c = s[i];
+ if (c != 0x0) return 0;
+ }
+
+ for (i = 10; i < 12; i++)
+ {
+ c = s[i];
+ if (c != 0xff) return 0;
+ }
+
+ return 1;
+}
+
+static int
+is_a4_compat(const char *s)
+{
+ int i;
+ u_int8_t c;
+
+ if (s == NULL) return 0;
+
+ for (i = 0; i < 12; i++)
+ {
+ c = s[i];
+ if (c != 0x0) return 0;
+ }
+
+ /* Check for :: and ::1 */
+ for (i = 13; i < 15; i++)
+ {
+ /* anything non-zero in these 3 bytes means it's a V4 address */
+ c = s[i];
+ if (c != 0x0) return 1;
+ }
+
+ /* Leading 15 bytes are all zero */
+ c = s[15];
+ if (c == 0x0) return 0;
+ if (c == 0x1) return 0;
+
+ return 1;
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int family, int *err)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, (family == AF_INET) ? inet_ntoa(*(struct in_addr *)src) : "-IPv6-");
+#endif
+
+ if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)src) || is_a4_compat((const char *)src)))
+ {
+ src += 12;
+ len = 4;
+ family = AF_INET;
+ }
+
+ item = si_host_byaddr(si_search(), src, family, (uint32_t *)err);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+#if 0
+static void
+si_libinfo_ipnode_callback(si_item_t *item, uint32_t status, void *ctx)
+{
+ si_context_t *sictx;
+ struct hostent *h;
+
+ if (ctx == NULL) return;
+
+ sictx = (si_context_t *)ctx;
+
+ if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
+ {
+ free(sictx);
+ si_item_release(item);
+ return;
+ }
+
+ if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
+
+ if (item == NULL)
+ {
+ ((si_ipnode_async_callback)(sictx->orig_callback))(NULL, status, sictx->orig_context);
+ return;
+ }
+
+ h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+ ((si_ipnode_async_callback)(sictx->orig_callback))(h, status, sictx->orig_context);
+
+ free(sictx);
+}
+
+mach_port_t
+getipnodebyaddr_async_call(const void *src, socklen_t len, int family, int *err, si_ipnode_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+ uint32_t srclen;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, (family == AF_INET) ? inet_ntoa(*(struct in_addr *)src) : "-IPv6-");
+#endif
+
+ if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)src) || is_a4_compat((const char *)src)))
+ {
+ src += 12;
+ len = 4;
+ family = AF_INET;
+ }
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_HOST;
+ sictx->key_offset = -1;
+
+ /* src is not a C string - pass length in num3 */
+ srclen = len;
+ return si_async_call(si_search(), SI_CALL_HOST_BYADDR, src, NULL, (uint32_t)family, 0, srclen, 0, (void *)si_libinfo_ipnode_callback, sictx);
+}
+
+mach_port_t
+getipnodebyaddr_async_start(const void *addr, size_t len, int family, int *error, si_ipnode_async_callback callback, void *context)
+{
+ socklen_t slen = len;
+
+ return getipnodebyaddr_async_call(addr, slen, family, error, callback, context);
+}
+
+void
+getipnodebyaddr_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+void
+getipnodebyaddr_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+getipnodebyaddr_async_handleReply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+#endif
+
+void
+sethostent(int ignored)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_HOST, NULL);
+}
+
+struct hostent *
+gethostent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_HOST);
+ if (list == NULL)
+ {
+ list = si_host_all(si_search());
+ LI_set_thread_list(CATEGORY_HOST, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endhostent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_HOST, NULL);
+}
+
+/* MAC ADDRESS */
+
+int
+ether_hostton(const char *name, struct ether_addr *e)
+{
+ si_item_t *item;
+ char *cmac;
+ uint32_t t[6];
+ int i;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ if (name == NULL) return -1;
+ if (e == NULL) return -1;
+
+ item = si_mac_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_MAC + 100, item);
+ if (item == NULL) return -1;
+
+ cmac = (char *)((uintptr_t)item + sizeof(si_item_t));
+
+ i = sscanf(cmac, " %x:%x:%x:%x:%x:%x", &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]);
+ if (i != 6) return -1;
+
+ for (i = 0; i < 6; i++) e->ether_addr_octet[i] = t[i];
+ return 0;
+}
+
+/* XXX to do? async ether_hostton */
+
+int ether_ntohost(char *name, const struct ether_addr *e)
+{
+ si_item_t *item;
+ char *cname;
+ uint32_t i, x[6];
+ char str[256];
+
+ if (name == NULL) return -1;
+ if (e == NULL) return -1;
+
+ for (i = 0; i < 6; i++) x[i] = e->ether_addr_octet[i];
+ snprintf(str, sizeof(str), "%x:%x:%x:%x:%x:%x", x[0], x[1], x[2], x[3], x[4], x[5]);
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, str);
+#endif
+
+ item = si_mac_bymac(si_search(), str);
+ LI_set_thread_item(CATEGORY_MAC + 200, item);
+ if (item == NULL) return -1;
+
+ cname = (char *)((uintptr_t)item + sizeof(si_item_t));
+
+ memcpy(name, cname, strlen(cname) + 1);
+ return 0;
+}
+
+/* XXX to do? async ether_ntohost */
+
+/* NETWORK */
+
+struct netent *
+getnetbyname(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_network_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_NETWORK + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getnetbyname_async_call(const char *name, si_network_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_NETWORK;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_NETWORK_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getnetbyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct netent *
+getnetbyaddr(uint32_t net, int type)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s 0x%08x\n", __func__, net);
+#endif
+
+ if (type != AF_INET) return NULL;
+
+ item = si_network_byaddr(si_search(), net);
+ LI_set_thread_item(CATEGORY_NETWORK + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getnetbyaddr_async_call(uint32_t net, int type, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s 0x%08x\n", __func__, net);
+#endif
+
+ if (type != AF_INET) return MACH_PORT_NULL;
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_NETWORK;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_NETWORK_BYADDR, NULL, NULL, net, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getnetbyaddr_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setnetent(int ignored)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_NETWORK, NULL);
+}
+
+struct netent *
+getnetent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_NETWORK);
+ if (list == NULL)
+ {
+ list = si_network_all(si_search());
+ LI_set_thread_list(CATEGORY_NETWORK, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endnetent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_NETWORK, NULL);
+}
+
+/* SERVICE */
+
+struct servent *
+getservbyname(const char *name, const char *proto)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %s\n", __func__, name, proto);
+#endif
+
+ item = si_service_byname(si_search(), name, proto);
+ LI_set_thread_item(CATEGORY_SERVICE + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getservbyname_async_call(const char *name, const char *proto, si_service_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s %s\n", __func__, name, proto);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_SERVICE;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_SERVICE_BYNAME, name, proto, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getservbyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct servent *
+getservbyport(int port, const char *proto)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d %s\n", __func__, ntohs((uint16_t)port), proto);
+#endif
+
+ item = si_service_byport(si_search(), port, proto);
+ LI_set_thread_item(CATEGORY_SERVICE + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getservbyport_async_call(int port, const char *proto, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %d %s\n", __func__, port, proto);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_SERVICE;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_SERVICE_BYPORT, NULL, proto, port, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getservbyport_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setservent(int ignored)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_SERVICE, NULL);
+}
+
+struct servent *
+getservent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_SERVICE);
+ if (list == NULL)
+ {
+ list = si_service_all(si_search());
+ LI_set_thread_list(CATEGORY_SERVICE, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endservent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_SERVICE, NULL);
+}
+
+/* PROTOCOL */
+
+struct protoent *
+getprotobyname(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_protocol_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_PROTOCOL + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getprotobyname_async_call(const char *name, si_protocol_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_PROTOCOL;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_PROTOCOL_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getprotobyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct protoent *
+getprotobynumber(int number)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d\n", __func__, number);
+#endif
+
+ item = si_protocol_bynumber(si_search(), number);
+ LI_set_thread_item(CATEGORY_PROTOCOL + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getprotobynumber_async_call(int number, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %d\n", __func__, number);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_PROTOCOL;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_PROTOCOL_BYNUMBER, NULL, NULL, number, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getprotobynumber_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setprotoent(int ignored)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_PROTOCOL, NULL);
+}
+
+struct protoent *
+getprotoent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_PROTOCOL);
+ if (list == NULL)
+ {
+ list = si_protocol_all(si_search());
+ LI_set_thread_list(CATEGORY_PROTOCOL, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endprotoent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_PROTOCOL, NULL);
+}
+
+/* RPC */
+
+struct rpcent *
+getrpcbyname(const char *name)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ item = si_rpc_byname(si_search(), name);
+ LI_set_thread_item(CATEGORY_RPC + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getrpcbyname_async_call(const char *name, si_rpc_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, name);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_RPC;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_RPC_BYNAME, name, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getrpcbyname_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct rpcent *
+getrpcbynumber
+(
+#ifdef __LP64__
+ int number
+#else
+ long number
+#endif
+)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %ld\n", __func__, (long int)number);
+#endif
+
+ item = si_rpc_bynumber(si_search(), number);
+ LI_set_thread_item(CATEGORY_RPC + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getrpcbynumber_async_call(int number, si_group_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %d\n", __func__, number);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_RPC;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_RPC_BYNUMBER, NULL, NULL, number, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getrpcbynumber_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+void
+setrpcent(int ignored)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_RPC, NULL);
+}
+
+struct rpcent *
+getrpcent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_RPC);
+ if (list == NULL)
+ {
+ list = si_rpc_all(si_search());
+ LI_set_thread_list(CATEGORY_RPC, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endrpcent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_RPC, NULL);
+}
+
+/* FS */
+
+struct fstab *
+getfsspec(const char *spec)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, spec);
+#endif
+
+ item = si_fs_byspec(si_search(), spec);
+ LI_set_thread_item(CATEGORY_FS + 100, item);
+ if (item == NULL) return NULL;
+
+ return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+struct fstab *
+getfsbyname(const char *name)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ return getfsspec(name);
+}
+
+mach_port_t
+getfsspec_async_call(const char *spec, si_fs_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, spec);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_FS;
+ sictx->key_offset = 100;
+
+ return si_async_call(si_search(), SI_CALL_FS_BYSPEC, spec, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getfsspec_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+struct fstab *
+getfsfile(const char *file)
+{
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, file);
+#endif
+
+ item = si_fs_byfile(si_search(), file);
+ LI_set_thread_item(CATEGORY_FS + 200, item);
+ if (item == NULL) return NULL;
+
+ return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+mach_port_t
+getfsfile_async_call(const char *file, si_fs_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s\n", __func__, file);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_FS;
+ sictx->key_offset = 200;
+
+ return si_async_call(si_search(), SI_CALL_FS_BYFILE, file, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
+}
+
+void
+getfsfile_async_handle_reply(mach_msg_header_t *msg)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ si_async_handle_reply(msg);
+}
+
+int
+setfsent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_FS, NULL);
+ return 1;
+}
+
+struct fstab *
+getfsent(void)
+{
+ si_list_t *list;
+ si_item_t *item;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ list = LI_get_thread_list(CATEGORY_FS);
+ if (list == NULL)
+ {
+ list = si_fs_all(si_search());
+ LI_set_thread_list(CATEGORY_FS, list);
+ }
+
+ item = si_list_next(list);
+ if (item == NULL) return NULL;
+
+ return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
+}
+
+void
+endfsent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ LI_set_thread_list(CATEGORY_FS, NULL);
+}
+
+/* GETADDRINFO */
+
+int
+getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
+{
+ si_list_t *list;
+ uint32_t family, socktype, protocol, flags, status;
+ struct addrinfo *ai;
+
+ family = AF_UNSPEC;
+ socktype = SOCK_UNSPEC;
+ protocol = IPPROTO_UNSPEC;
+ flags = 0;
+ status = SI_STATUS_NO_ERROR;
+
+ if (res == NULL) return 0;
+ *res = NULL;
+
+ if (hints != NULL)
+ {
+ family = hints->ai_family;
+ socktype = hints->ai_socktype;
+ protocol = hints->ai_protocol;
+ flags = hints->ai_flags;
+ }
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s %s %u %u %u 0x%08x\n", __func__, nodename, servname, family, socktype, protocol, flags);
+#endif
+
+ list = si_addrinfo(si_search(), nodename, servname, family, socktype, protocol, flags, &status);
+ if ((status != SI_STATUS_NO_ERROR) || (list == NULL))
+ {
+ si_list_release(list);
+
+ if (status == SI_STATUS_NO_ERROR) return EAI_NONAME;
+ else if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
+ else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
+ else status = status - SI_STATUS_EAI_PLUS_100;
+ return status;
+ }
+
+ *res = si_list_to_addrinfo(list);
+ si_list_release(list);
+ if (*res == NULL) status = EAI_MEMORY;
+
+ /* don't return the canonical name unless asked */
+ if ((flags & AI_CANONNAME) == 0)
+ {
+ for (ai = *res; ai != NULL; ai = ai->ai_next)
+ {
+ free(ai->ai_canonname);
+ ai->ai_canonname = NULL;
+ }
+ }
+
+ return status;
+}
+
+#ifdef CALL_TRACE
+
+static char *
+socket_name(int sock)
+{
+ static char str[16];
+
+ switch(sock)
+ {
+ case SOCK_UNSPEC: return "SOCK_UNSPEC";
+ case SOCK_STREAM: return "SOCK_STREAM";
+ case SOCK_DGRAM: return "SOCK_DGRAM";
+ }
+
+ sprintf(str, "%d", sock);
+ return str;
+}
+
+static char *
+family_name(int pf)
+{
+ static char str[16];
+
+ switch(pf)
+ {
+ case PF_UNSPEC: return "PF_UNSPEC";
+ case PF_INET: return "PF_INET";
+ case PF_INET6: return "PF_INET6";
+ };
+
+ sprintf(str, "%d", pf);
+ return str;
+}
+
+static char *
+protocol_name(int p)
+{
+ static char str[16];
+
+ switch(p)
+ {
+ case IPPROTO_UNSPEC: return "IPPROTO_UNSPEC";
+ case IPPROTO_TCP: return "IPPROTO_TCP";
+ case IPPROTO_UDP: return "IPPROTO_UDP";
+ }
+
+ sprintf(str, "%d", p);
+ return str;
+}
+
+static char *
+_gai_inet_ntop(struct in6_addr a)
+{
+ static char buf[128];
+ char t[32];
+ unsigned short x;
+ char *p;
+ int i;
+
+ memset(buf, 0, 128);
+
+ p = (char *)&a.__u6_addr.__u6_addr32;
+ for (i = 0; i < 8; i++, x += 1)
+ {
+ memmove(&x, p, 2);
+ p += 2;
+ sprintf(t, "%hx", x);
+ strcat(buf, t);
+ if (i < 7) strcat(buf, ":");
+ }
+
+ return buf;
+}
+
+static void
+fprint_addrinfo(FILE *f, struct addrinfo *a)
+{
+ int i;
+ unsigned char v;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+
+ if (a == NULL) return;
+
+ if (a->ai_flags != 0)
+ {
+ fprintf(f, "flags =");
+ if (a->ai_flags & AI_PASSIVE) fprintf(f, " AI_PASSIVE");
+ if (a->ai_flags & AI_CANONNAME) fprintf(f, " AI_CANONNAME");
+ if (a->ai_flags & AI_NUMERICHOST) fprintf(f, " AI_NUMERICHOST");
+ if (a->ai_flags & AI_NUMERICSERV) fprintf(f, " AI_NUMERICSERV");
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "family = %s\n", family_name(a->ai_family));
+ fprintf(f, "socktype = %s\n", socket_name(a->ai_socktype));
+ fprintf(f, "protocol = %s\n", protocol_name(a->ai_protocol));
+
+ fprintf(f, "canonical name = ");
+ if (a->ai_canonname == NULL) fprintf(f, "NULL\n");
+ else fprintf(f, "\"%s\"\n", a->ai_canonname);
+
+ fprintf(f, "addrlen = %ld\n", (long int)a->ai_addrlen);
+
+ if (a->ai_addr == NULL) fprintf(f, "sockaddr = NULL\n");
+ else
+ {
+ if (a->ai_family == PF_INET)
+ {
+ s4 = (struct sockaddr_in *)a->ai_addr;
+
+ fprintf(f, "sockaddr_in len = %d\n", s4->sin_len);
+ fprintf(f, "sockaddr_in family = %s\n", family_name(s4->sin_family));
+ fprintf(f, "sockaddr_in port = %hu\n", ntohs(s4->sin_port));
+ fprintf(f, "sockaddr_in address = %s\n", inet_ntoa(s4->sin_addr));
+ }
+ else if (a->ai_family == PF_INET6)
+ {
+ s6 = (struct sockaddr_in6 *)a->ai_addr;
+
+ fprintf(f, "sockaddr_in6 len = %d\n", s6->sin6_len);
+ fprintf(f, "sockaddr_in6 family = %s\n", family_name(s6->sin6_family));
+ fprintf(f, "sockaddr_in6 port = %hu\n", ntohs(s6->sin6_port));
+ fprintf(f, "sockaddr_in6 flowinfo = %d\n", s6->sin6_flowinfo);
+ fprintf(f, "sockaddr_in6 address = %s\n", _gai_inet_ntop(s6->sin6_addr));
+ fprintf(f, "sockaddr_in6 scope_id = %d\n", s6->sin6_scope_id);
+ }
+ else
+ {
+ fprintf(f, "sockaddr len = %d\n", a->ai_addr->sa_len);
+ fprintf(f, "sockaddr family = %s\n", family_name(a->ai_addr->sa_family));
+ fprintf(f, "sockaddr data = ");
+ for (i = 0; i < a->ai_addr->sa_len - 2; i++)
+ {
+ v = a->ai_addr->sa_data[i];
+ fprintf(f, "%02x", v);
+ }
+ fprintf(f, "\n");
+ }
+ }
+
+ if (a->ai_next != NULL)
+ {
+ fprintf(f, "NEXT --->\n");
+ fprint_addrinfo(f, a->ai_next);
+ }
+}
+
+#endif
+
+static void
+si_libinfo_addrinfo_callback(si_list_t *list, uint32_t status, void *ctx)
+{
+ si_context_t *sictx;
+ struct addrinfo *out;
+
+ if (ctx == NULL)
+ {
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s error no context\n", __func__);
+#endif
+ si_list_release(list);
+ return;
+ }
+
+ sictx = (si_context_t *)ctx;
+
+ if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
+ {
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s error no callback\n", __func__);
+#endif
+ si_list_release(list);
+ free(sictx);
+ return;
+ }
+
+ if (status != SI_STATUS_NO_ERROR)
+ {
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s original status %d\n", __func__, status);
+#endif
+ if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
+ else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
+ else status = status - SI_STATUS_EAI_PLUS_100;
+ }
+
+ if (list == NULL)
+ {
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s result NULL status %d (returning EAI_NONAME)\n", __func__, status);
+#endif
+ ((si_addrinfo_async_callback)(sictx->orig_callback))(EAI_NONAME, NULL, sictx->orig_context);
+ free(sictx);
+ return;
+ }
+
+ out = si_list_to_addrinfo(list);
+ si_list_release(list);
+ if (out == NULL)
+ {
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s result conversion failed returning NULL status %d (returning EAI_MEMORY)\n", __func__, status);
+#endif
+ ((si_addrinfo_async_callback)(sictx->orig_callback))(EAI_MEMORY, NULL, sictx->orig_context);
+ free(sictx);
+ return;
+ }
+
+#ifdef CALL_TRACE
+ fprintf(stderr, " %s %d\n", __func__, status);
+ fprint_addrinfo(stderr, out);
+#endif
+ ((si_addrinfo_async_callback)(sictx->orig_callback))(status, out, sictx->orig_context);
+
+ free(sictx);
+}
+
+mach_port_t
+getaddrinfo_async_call(const char *nodename, const char *servname, const struct addrinfo *hints, si_addrinfo_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+ uint32_t family, socktype, protocol, flags;
+
+ family = AF_UNSPEC;
+ socktype = SOCK_UNSPEC;
+ protocol = IPPROTO_UNSPEC;
+ flags = 0;
+
+ if (hints != NULL)
+ {
+ family = hints->ai_family;
+ socktype = hints->ai_socktype;
+ protocol = hints->ai_protocol;
+ flags = hints->ai_flags;
+ }
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s %s %s %u %u %u 0x%08x\n", __func__, nodename, servname, family, socktype, protocol, flags);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_ADDRINFO;
+ sictx->key_offset = 0;
+
+ return si_async_call(si_search(), SI_CALL_ADDRINFO, nodename, servname, family, socktype, protocol, flags, (void *)si_libinfo_addrinfo_callback, sictx);
+}
+
+int32_t
+getaddrinfo_async_start(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints, si_addrinfo_async_callback callback, void *context)
+{
+ if (p == NULL) return EAI_SYSTEM;
+
+ *p = getaddrinfo_async_call(nodename, servname, hints, callback, context);
+
+ if (*p == MACH_PORT_NULL) return EAI_SYSTEM;
+ return 0;
+}
+
+int32_t
+getaddrinfo_async_send(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints)
+{
+ return getaddrinfo_async_start(p, nodename, servname, hints, NULL, NULL);
+}
+
+int32_t
+getaddrinfo_async_receive(mach_port_t p, struct addrinfo **res)
+{
+ /* unsupported Leopard SPI */
+ return EAI_SYSTEM;
+}
+
+void
+getaddrinfo_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+int32_t
+getaddrinfo_async_handle_reply(void *param)
+{
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+
+ return 0;
+}
+
+/* GETNAMEINFO */
+
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags)
+{
+ si_item_t *item;
+ si_nameinfo_t *ni;
+ uint32_t status, len, wantn, wants;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s\n", __func__);
+#endif
+
+ status = SI_STATUS_NO_ERROR;
+
+ wantn = 0;
+ if ((node != NULL) && (nodelen > 0)) wantn = 1;
+
+ wants = 0;
+ if ((service != NULL) && (servicelen > 0)) wants = 1;
+
+ if ((wantn == 0) && (wants == 0)) return status;
+
+ if (wantn == 0) flags |= NI_NUMERICHOST;
+ if (wants == 0) flags |= NI_NUMERICSERV;
+
+ item = si_nameinfo(si_search(), sa, flags, &status);
+ if ((status != SI_STATUS_NO_ERROR) || (item == NULL))
+ {
+ si_item_release(item);
+
+ if (status == SI_STATUS_NO_ERROR) status = EAI_NONAME;
+ else if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
+ else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
+ else status = status - SI_STATUS_EAI_PLUS_100;
+ return status;
+ }
+
+ ni = (si_nameinfo_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ len = 0;
+ if (ni->ni_node != NULL) len = strlen(ni->ni_node) + 1;
+ if ((wantn == 1) && (len > 0))
+ {
+ if (len > nodelen)
+ {
+ si_item_release(item);
+ return EAI_OVERFLOW;
+ }
+
+ memset(node, 0, nodelen);
+ memcpy(node, ni->ni_node, len);
+ }
+
+ len = 0;
+ if (ni->ni_serv != NULL) len = strlen(ni->ni_serv) + 1;
+ if ((wants == 1) && (len > 0))
+ {
+ if (len > servicelen)
+ {
+ si_item_release(item);
+ return EAI_OVERFLOW;
+ }
+
+ memset(service, 0, servicelen);
+ memcpy(service, ni->ni_serv, len);
+ }
+
+ si_item_release(item);
+ return 0;
+}
+
+static void
+si_libinfo_nameinfo_callback(si_item_t *item, uint32_t status, void *ctx)
+{
+ si_context_t *sictx;
+ si_nameinfo_t *ni;
+ char *node, *serv;
+
+ if (ctx == NULL) return;
+
+ sictx = (si_context_t *)ctx;
+
+ if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
+ {
+ si_item_release(item);
+ free(sictx);
+ return;
+ }
+
+ if (status != SI_STATUS_NO_ERROR)
+ {
+ if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
+ else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
+ else status = status - SI_STATUS_EAI_PLUS_100;
+ }
+
+ if (item == NULL)
+ {
+ ((si_nameinfo_async_callback)(sictx->orig_callback))(status, NULL, NULL, sictx->orig_context);
+ free(sictx);
+ return;
+ }
+
+ LI_set_thread_item(CATEGORY_NAMEINFO, item);
+
+ node = NULL;
+ serv = NULL;
+
+ ni = (si_nameinfo_t *)((uintptr_t)item + sizeof(si_item_t));
+ if (ni->ni_node != NULL) node = strdup(ni->ni_node);
+ if (ni->ni_serv != NULL) serv = strdup(ni->ni_serv);
+
+ ((si_nameinfo_async_callback)(sictx->orig_callback))(status, node, serv, sictx->orig_context);
+ free(sictx);
+}
+
+mach_port_t
+getnameinfo_async_call(const struct sockaddr *sa, size_t len, int flags, si_nameinfo_async_callback callback, void *context)
+{
+ si_context_t *sictx;
+ uint32_t salen;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, ">> %s\n", __func__);
+#endif
+
+ sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
+ if (sictx == NULL) return MACH_PORT_NULL;
+
+ sictx->orig_callback = callback;
+ sictx->orig_context = context;
+ sictx->cat = CATEGORY_ADDRINFO;
+ sictx->key_offset = 0;
+
+ /* sa is not a C string - pass length in num3 */
+ salen = len;
+ return si_async_call(si_search(), SI_CALL_NAMEINFO, (const char *)sa, NULL, flags, 0, salen, 0, (void *)si_libinfo_nameinfo_callback, sictx);
+}
+
+int32_t
+getnameinfo_async_start(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags, si_nameinfo_async_callback callback, void *context)
+{
+ if (p == NULL) return EAI_SYSTEM;
+ *p = getnameinfo_async_call(sa, salen, flags, callback, context);
+
+ if (*p == MACH_PORT_NULL) return EAI_SYSTEM;
+ return 0;
+}
+
+int32_t
+getnameinfo_async_send(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags)
+{
+ return getnameinfo_async_start(p, sa, salen, flags, NULL, NULL);
+}
+
+void
+getnameinfo_async_cancel(mach_port_t p)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "-- %s\n", __func__);
+#endif
+
+ si_async_cancel(p);
+}
+
+int32_t
+getnameinfo_async_handle_reply(void *param)
+{
+ mach_msg_header_t *msg;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "<< %s\n", __func__);
+#endif
+
+ msg = (mach_msg_header_t *)param;
+ si_async_handle_reply(msg);
+
+ return 0;
+}
+
+/* getpwXXX_r and getgrXXX_r */
+
+static int
+copy_user_r(struct passwd *in, struct passwd *out, char *buffer, int buflen)
+{
+ int hsize;
+ char *bp;
+
+ if (in == NULL) return -1;
+ if (out == NULL) return -1;
+
+ if (buffer == NULL) buflen = 0;
+
+ /* Calculate size of input */
+ hsize = 0;
+ if (in->pw_name != NULL) hsize += (strlen(in->pw_name) + 1);
+ if (in->pw_passwd != NULL) hsize += (strlen(in->pw_passwd) + 1);
+ if (in->pw_class != NULL) hsize += (strlen(in->pw_class) + 1);
+ if (in->pw_gecos != NULL) hsize += (strlen(in->pw_gecos) + 1);
+ if (in->pw_dir != NULL) hsize += (strlen(in->pw_dir) + 1);
+ if (in->pw_shell != NULL) hsize += (strlen(in->pw_shell) + 1);
+
+ /* Check buffer space */
+ if (hsize > buflen) return -1;
+
+ /* Copy result into caller's struct passwd, using buffer for memory */
+ bp = buffer;
+
+ out->pw_name = NULL;
+ if (in->pw_name != NULL)
+ {
+ out->pw_name = bp;
+ hsize = strlen(in->pw_name) + 1;
+ memmove(bp, in->pw_name, hsize);
+ bp += hsize;
+ }
+
+ out->pw_passwd = NULL;
+ if (in->pw_passwd != NULL)
+ {
+ out->pw_passwd = bp;
+ hsize = strlen(in->pw_passwd) + 1;
+ memmove(bp, in->pw_passwd, hsize);
+ bp += hsize;
+ }
+
+ out->pw_uid = in->pw_uid;
+
+ out->pw_gid = in->pw_gid;
+
+ out->pw_change = in->pw_change;
+
+ out->pw_class = NULL;
+ if (in->pw_class != NULL)
+ {
+ out->pw_class = bp;
+ hsize = strlen(in->pw_class) + 1;
+ memmove(bp, in->pw_class, hsize);
+ bp += hsize;
+ }
+
+ out->pw_gecos = NULL;
+ if (in->pw_gecos != NULL)
+ {
+ out->pw_gecos = bp;
+ hsize = strlen(in->pw_gecos) + 1;
+ memmove(bp, in->pw_gecos, hsize);
+ bp += hsize;
+ }
+
+ out->pw_dir = NULL;
+ if (in->pw_dir != NULL)
+ {
+ out->pw_dir = bp;
+ hsize = strlen(in->pw_dir) + 1;
+ memmove(bp, in->pw_dir, hsize);
+ bp += hsize;
+ }
+
+ out->pw_shell = NULL;
+ if (in->pw_shell != NULL)
+ {
+ out->pw_shell = bp;
+ hsize = strlen(in->pw_shell) + 1;
+ memmove(bp, in->pw_shell, hsize);
+ bp += hsize;
+ }
+
+ out->pw_expire = in->pw_expire;
+
+ return 0;
+}
+
+static int
+copy_group_r(struct group *in, struct group *out, char *buffer, int buflen)
+{
+ int i, len, hsize;
+ unsigned long addr;
+ char *bp, *ap;
+
+ if (in == NULL) return -1;
+ if (out == NULL) return -1;
+
+ if (buffer == NULL) buflen = 0;
+
+ /* Calculate size of input */
+ hsize = 0;
+ if (in->gr_name != NULL) hsize += (strlen(in->gr_name) + 1);
+ if (in->gr_passwd != NULL) hsize += (strlen(in->gr_passwd) + 1);
+
+ /* NULL pointer at end of list */
+ hsize += sizeof(char *);
+
+ len = 0;
+ if (in->gr_mem != NULL)
+ {
+ for (len = 0; in->gr_mem[len] != NULL; len++)
+ {
+ hsize += sizeof(char *);
+ hsize += (strlen(in->gr_mem[len]) + 1);
+ }
+ }
+
+ /* Check buffer space */
+ if (hsize > buflen) return -1;
+
+ /* Copy result into caller's struct group, using buffer for memory */
+ bp = buffer;
+
+ out->gr_name = NULL;
+ if (in->gr_name != NULL)
+ {
+ out->gr_name = bp;
+ hsize = strlen(in->gr_name) + 1;
+ memmove(bp, in->gr_name, hsize);
+ bp += hsize;
+ }
+
+ out->gr_passwd = NULL;
+ if (in->gr_passwd != NULL)
+ {
+ out->gr_passwd = bp;
+ hsize = strlen(in->gr_passwd) + 1;
+ memmove(bp, in->gr_passwd, hsize);
+ bp += hsize;
+ }
+
+ out->gr_gid = in->gr_gid;
+
+ out->gr_mem = NULL;
+ ap = bp + ((len + 1) * sizeof(char *));
+
+ if (in->gr_mem != NULL)
+ {
+ out->gr_mem = (char **)bp;
+ for (i = 0; i < len; i++)
+ {
+ addr = (unsigned long)ap;
+ memmove(bp, &addr, sizeof(unsigned long));
+ bp += sizeof(unsigned long);
+
+ hsize = strlen(in->gr_mem[i]) + 1;
+ memmove(ap, in->gr_mem[i], hsize);
+ ap += hsize;
+ }
+ }
+
+ memset(bp, 0, sizeof(unsigned long));
+ bp = ap;
+
+ return 0;
+}
+
+int
+getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result)
+{
+ si_item_t *item;
+ struct group *g;
+ int status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ if (result != NULL) *result = NULL;
+
+ if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+
+ item = si_group_byname(si_search(), name);
+ if (item == NULL) return 0;
+
+ g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
+
+ status = copy_group_r(g, grp, buffer, bufsize);
+ si_item_release(item);
+
+ if (status != 0) return ERANGE;
+
+ *result = grp;
+ return 0;
+}
+
+int
+getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
+{
+ si_item_t *item;
+ struct group *g;
+ int status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d\n", __func__, gid);
+#endif
+
+ if (result != NULL) *result = NULL;
+
+ if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+
+ item = si_group_bygid(si_search(), gid);
+ if (item == NULL) return 0;
+
+ g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
+
+ status = copy_group_r(g, grp, buffer, bufsize);
+ si_item_release(item);
+
+ if (status != 0) return ERANGE;
+
+ *result = grp;
+ return 0;
+}
+
+int
+getpwnam_r(const char *name, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
+{
+ si_item_t *item;
+ struct passwd *p;
+ int status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %s\n", __func__, name);
+#endif
+
+ if (result != NULL) *result = NULL;
+
+ if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+
+ item = si_user_byname(si_search(), name);
+ if (item == NULL) return 0;
+
+ p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+
+ status = copy_user_r(p, pw, buffer, bufsize);
+ si_item_release(item);
+
+ if (status != 0) return ERANGE;
+
+ *result = pw;
+ return 0;
+}
+
+int
+getpwuid_r(uid_t uid, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
+{
+ si_item_t *item;
+ struct passwd *p;
+ int status;
+
+#ifdef CALL_TRACE
+ fprintf(stderr, "-> %s %d\n", __func__, uid);
+#endif
+
+ if (result != NULL) *result = NULL;
+
+ if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
+
+ item = si_user_byuid(si_search(), uid);
+ if (item == NULL) return 0;
+
+ p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+
+ status = copy_user_r(p, pw, buffer, bufsize);
+ si_item_release(item);
+
+ if (status != 0) return ERANGE;
+
+ *result = pw;
+ return 0;
+}
+
+/* misc */
+
+char *
+user_from_uid(uid_t uid, int nouser)
+{
+ struct passwd *pw;
+ static char buf[16];
+
+ pw = getpwuid(uid);
+ if (pw != NULL) return pw->pw_name;
+
+ if (nouser) return NULL;
+
+ snprintf(buf, sizeof(buf), "%u", uid);
+ return buf;
+}
+
+char *
+group_from_gid(gid_t gid, int nogroup)
+{
+ struct group *gr;
+ static char buf[16];
+
+ gr = getgrgid(gid);
+ if (gr != NULL) return gr->gr_name;
+
+ if (nogroup) return NULL;
+
+ snprintf(buf, sizeof(buf), "%u", gid);
+ return buf;
+}
+
+/* no longer supported */
+
+const prdb_ent *
+prdb_getbyname(const char *name)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return NULL;
+}
+
+const prdb_ent *
+prdb_get(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return NULL;
+}
+
+void
+prdb_set(const char *name)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+}
+
+void
+prdb_end(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+}
+
+struct bootparamsent *
+bootparams_getbyname(const char *name)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return NULL;
+}
+
+struct bootparamsent *
+bootparams_getent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return NULL;
+}
+
+void
+bootparams_setent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+}
+
+void
+bootparams_endent(void)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+}
+
+int
+bootp_getbyether(struct ether_addr *enaddr, char **name,struct in_addr *ipaddr, char **bootfile)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return 0;
+}
+
+int
+bootp_getbyip(struct ether_addr *enaddr, char **name, struct in_addr *ipaddr, char **bootfile)
+{
+#ifdef CALL_TRACE
+ fprintf(stderr, "~~ %s\n", __func__);
+#endif
+ return 0;
+}
+