int seccomp_restrict_namespaces(unsigned long retain) {
        uint32_t arch;
        int r;

        if (DEBUG_LOGGING) {
                _cleanup_free_ char *s = NULL;

                (void) namespace_flags_to_string(retain, &s);
                log_debug("Restricting namespace to: %s.", strna(s));
        }

        /* NOOP? */
        if ((retain & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
                return 0;

        SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
                unsigned i;

                log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));

                r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
                if (r < 0)
                        return r;

                if ((retain & NAMESPACE_FLAGS_ALL) == 0)
                        /* If every single kind of namespace shall be prohibited, then let's block the whole setns() syscall
                         * altogether. */
                        r = seccomp_rule_add_exact(
                                        seccomp,
                                        SCMP_ACT_ERRNO(EPERM),
                                        SCMP_SYS(setns),
                                        0);
                else
                        /* Otherwise, block only the invocations with the appropriate flags in the loop below, but also the
                         * special invocation with a zero flags argument, right here. */
                        r = seccomp_rule_add_exact(
                                        seccomp,
                                        SCMP_ACT_ERRNO(EPERM),
                                        SCMP_SYS(setns),
                                        1,
                                        SCMP_A1(SCMP_CMP_EQ, 0));
                if (r < 0) {
                        log_debug_errno(r, "Failed to add setns() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
                        continue;
                }

                for (i = 0; namespace_flag_map[i].name; i++) {
                        unsigned long f;

                        f = namespace_flag_map[i].flag;
                        if ((retain & f) == f) {
                                log_debug("Permitting %s.", namespace_flag_map[i].name);
                                continue;
                        }

                        log_debug("Blocking %s.", namespace_flag_map[i].name);

                        r = seccomp_rule_add_exact(
                                        seccomp,
                                        SCMP_ACT_ERRNO(EPERM),
                                        SCMP_SYS(unshare),
                                        1,
                                        SCMP_A0(SCMP_CMP_MASKED_EQ, f, f));
                        if (r < 0) {
                                log_debug_errno(r, "Failed to add unshare() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
                                break;
                        }

                        /* On s390/s390x the first two parameters to clone are switched */
                        if (!IN_SET(arch, SCMP_ARCH_S390, SCMP_ARCH_S390X))
                                r = seccomp_rule_add_exact(
                                                seccomp,
                                                SCMP_ACT_ERRNO(EPERM),
                                                SCMP_SYS(clone),
                                                1,
                                                SCMP_A0(SCMP_CMP_MASKED_EQ, f, f));
                        else
                                r = seccomp_rule_add_exact(
                                                seccomp,
                                                SCMP_ACT_ERRNO(EPERM),
                                                SCMP_SYS(clone),
                                                1,
                                                SCMP_A1(SCMP_CMP_MASKED_EQ, f, f));
                        if (r < 0) {
                                log_debug_errno(r, "Failed to add clone() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
                                break;
                        }

                        if ((retain & NAMESPACE_FLAGS_ALL) != 0) {
                                r = seccomp_rule_add_exact(
                                                seccomp,
                                                SCMP_ACT_ERRNO(EPERM),
                                                SCMP_SYS(setns),
                                                1,
                                                SCMP_A1(SCMP_CMP_MASKED_EQ, f, f));
                                if (r < 0) {
                                        log_debug_errno(r, "Failed to add setns() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
                                        break;
                                }
                        }
                }
                if (r < 0)
                        continue;

                r = seccomp_load(seccomp);
                if (IN_SET(r, -EPERM, -EACCES))
                        return r;
                if (r < 0)
                        log_debug_errno(r, "Failed to install namespace restriction rules for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
        }

        return 0;
}


static int property_get_syscall_filter(
                sd_bus *bus,
                const char *path,
                const char *interface,
                const char *property,
                sd_bus_message *reply,
                void *userdata,
                sd_bus_error *error) {

        ExecContext *c = userdata;
        _cleanup_strv_free_ char **l = NULL;
        int r;

#if HAVE_SECCOMP
        Iterator i;
        void *id, *val;
#endif

        assert(bus);
        assert(reply);
        assert(c);

        r = sd_bus_message_open_container(reply, 'r', "bas");
        if (r < 0)
                return r;

        r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
        if (r < 0)
                return r;

#if HAVE_SECCOMP
        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter, i) {
                _cleanup_free_ char *name = NULL;
                const char *e = NULL;
                char *s;
                int num = PTR_TO_INT(val);

                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
                if (!name)
                        continue;

                if (num >= 0) {
                        e = errno_to_name(num);
                        if (e) {
                                s = strjoin(name, ":", e);
                                if (!s)
                                        return -ENOMEM;
                        } else {
                                r = asprintf(&s, "%s:%d", name, num);
                                if (r < 0)
                                        return -ENOMEM;
                        }
                } else
                        s = TAKE_PTR(name);

                r = strv_consume(&l, s);
                if (r < 0)
                        return r;
        }
#endif

        strv_sort(l);

        r = sd_bus_message_append_strv(reply, l);
        if (r < 0)
                return r;

        return sd_bus_message_close_container(reply);
}


void exec_command_reset_status_array(ExecCommand *c, size_t n) {
        size_t i;

        for (i = 0; i < n; i++)
                exec_status_reset(&c[i].exec_status);
}


static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
        assert(u);
        assert(c);

        /* Turn off the legacy sysctl() system call. Many distributions turn this off while building the kernel, but
         * let's protect even those systems where this is left on in the kernel. */

        if (!c->protect_kernel_tunables)
                return 0;

        if (skip_seccomp_unavailable(u, "ProtectKernelTunables="))
                return 0;

        return seccomp_protect_sysctl();
}


void exec_command_done_array(ExecCommand *c, size_t n) {
        size_t i;

        for (i = 0; i < n; i++)
                exec_command_done(c+i);
}


static int property_get_temporary_filesystems(
                sd_bus *bus,
                const char *path,
                const char *interface,
                const char *property,
                sd_bus_message *reply,
                void *userdata,
                sd_bus_error *error) {

        ExecContext *c = userdata;
        unsigned i;
        int r;

        assert(bus);
        assert(c);
        assert(property);
        assert(reply);

        r = sd_bus_message_open_container(reply, 'a', "(ss)");
        if (r < 0)
                return r;

        for (i = 0; i < c->n_temporary_filesystems; i++) {
                TemporaryFileSystem *t = c->temporary_filesystems + i;

                r = sd_bus_message_append(
                                reply, "(ss)",
                                t->path,
                                t->options);
                if (r < 0)
                        return r;
        }

        return sd_bus_message_close_container(reply);
}


static int close_remaining_fds(
                const ExecParameters *params,
                const ExecRuntime *runtime,
                const DynamicCreds *dcreds,
                int user_lookup_fd,
                int socket_fd,
                int exec_fd,
                int *fds, size_t n_fds) {

        size_t n_dont_close = 0;
        int dont_close[n_fds + 12];

        assert(params);

        if (params->stdin_fd >= 0)
                dont_close[n_dont_close++] = params->stdin_fd;
        if (params->stdout_fd >= 0)
                dont_close[n_dont_close++] = params->stdout_fd;
        if (params->stderr_fd >= 0)
                dont_close[n_dont_close++] = params->stderr_fd;

        if (socket_fd >= 0)
                dont_close[n_dont_close++] = socket_fd;
        if (exec_fd >= 0)
                dont_close[n_dont_close++] = exec_fd;
        if (n_fds > 0) {
                memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
                n_dont_close += n_fds;
        }

        if (runtime)
                append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);

        if (dcreds) {
                if (dcreds->user)
                        append_socket_pair(dont_close, &n_dont_close, dcreds->user->storage_socket);
                if (dcreds->group)
                        append_socket_pair(dont_close, &n_dont_close, dcreds->group->storage_socket);
        }

        if (user_lookup_fd >= 0)
                dont_close[n_dont_close++] = user_lookup_fd;

        return close_all_fds(dont_close, n_dont_close);
}


static int build_pass_environment(const ExecContext *c, char ***ret) {
        _cleanup_strv_free_ char **pass_env = NULL;
        size_t n_env = 0, n_bufsize = 0;
        char **i;

        STRV_FOREACH(i, c->pass_environment) {
                _cleanup_free_ char *x = NULL;
                char *v;

                v = getenv(*i);
                if (!v)
                        continue;
                x = strjoin(*i, "=", v);
                if (!x)
                        return -ENOMEM;

                if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
                        return -ENOMEM;

                pass_env[n_env++] = TAKE_PTR(x);
                pass_env[n_env] = NULL;
        }

        *ret = TAKE_PTR(pass_env);

        return 0;
}


int exec_context_get_effective_ioprio(const ExecContext *c) {
        int p;

        assert(c);

        if (c->ioprio_set)
                return c->ioprio;

        p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
        if (p < 0)
                return IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);

        return p;
}


static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
        char *n;
        usec_t t;
        size_t l;
        int r;

        r = parse_sec(eq, &t);
        if (r < 0)
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);

        l = strlen(field);
        n = newa(char, l + 2);
        /* Change suffix Sec → USec */
        strcpy(mempcpy(n, field, l - 3), "USec");

        r = sd_bus_message_append(m, "(sv)", n, "t", t);
        if (r < 0)
                return bus_log_create_error(r);

        return 1;
}


static int fixup_input(
                const ExecContext *context,
                int socket_fd,
                bool apply_tty_stdin) {

        ExecInput std_input;

        assert(context);

        std_input = context->std_input;

        if (is_terminal_input(std_input) && !apply_tty_stdin)
                return EXEC_INPUT_NULL;

        if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
                return EXEC_INPUT_NULL;

        if (std_input == EXEC_INPUT_DATA && context->stdin_data_size == 0)
                return EXEC_INPUT_NULL;

        return std_input;
}


static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
        const char *p;
        int r;

        r = sd_bus_message_open_container(m, 'r', "sv");
        if (r < 0)
                return bus_log_create_error(r);

        r = sd_bus_message_append_basic(m, 's', field);
        if (r < 0)
                return bus_log_create_error(r);

        r = sd_bus_message_open_container(m, 'v', "as");
        if (r < 0)
                return bus_log_create_error(r);

        r = sd_bus_message_open_container(m, 'a', "s");
        if (r < 0)
                return bus_log_create_error(r);

        for (p = eq;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&p, &word, NULL, flags);
                if (r == 0)
                        break;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0)
                        return log_error_errno(r, "Invalid syntax: %s", eq);

                r = sd_bus_message_append_basic(m, 's', word);
                if (r < 0)
                        return bus_log_create_error(r);
        }

        r = sd_bus_message_close_container(m);
        if (r < 0)
                return bus_log_create_error(r);

        r = sd_bus_message_close_container(m);
        if (r < 0)
                return bus_log_create_error(r);

        r = sd_bus_message_close_container(m);
        if (r < 0)
                return bus_log_create_error(r);

        return 1;
}


const char* exec_context_fdname(const ExecContext *c, int fd_index) {
        assert(c);

        switch (fd_index) {

        case STDIN_FILENO:
                if (c->std_input != EXEC_INPUT_NAMED_FD)
                        return NULL;

                return c->stdio_fdname[STDIN_FILENO] ?: "stdin";

        case STDOUT_FILENO:
                if (c->std_output != EXEC_OUTPUT_NAMED_FD)
                        return NULL;

                return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";

        case STDERR_FILENO:
                if (c->std_error != EXEC_OUTPUT_NAMED_FD)
                        return NULL;

                return c->stdio_fdname[STDERR_FILENO] ?: "stderr";

        default:
                return NULL;
        }
}


static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {

        if (STR_IN_SET(field, "What", "Where", "Options", "Type"))

                return bus_append_string(m, field, eq);

        if (streq(field, "TimeoutSec"))

                return bus_append_parse_sec_rename(m, field, eq);

        if (streq(field, "DirectoryMode"))

                return bus_append_parse_mode(m, field, eq);

        if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))

                return bus_append_parse_boolean(m, field, eq);

        return 0;
}


static bool context_has_no_new_privileges(const ExecContext *c) {
        assert(c);

        if (c->no_new_privileges)
                return true;

        if (have_effective_cap(CAP_SYS_ADMIN)) /* if we are privileged, we don't need NNP */
                return false;

        /* We need NNP if we have any form of seccomp and are unprivileged */
        return context_has_address_families(c) ||
                c->memory_deny_write_execute ||
                c->restrict_realtime ||
                c->restrict_suid_sgid ||
                exec_context_restrict_namespaces_set(c) ||
                c->protect_kernel_tunables ||
                c->protect_kernel_modules ||
                c->private_devices ||
                context_has_syscall_filters(c) ||
                !set_isempty(c->syscall_archs) ||
                c->lock_personality ||
                c->protect_hostname;
}


static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids) {
        int r;

        /* Handle SupplementaryGroups= if it is not empty */
        if (ngids > 0) {
                r = maybe_setgroups(ngids, supplementary_gids);
                if (r < 0)
                        return r;
        }

        if (gid_is_valid(gid)) {
                /* Then set our gids */
                if (setresgid(gid, gid, gid) < 0)
                        return -errno;
        }

        return 0;
}


static int property_get_smack_process_label(
                sd_bus *bus,
                const char *path,
                const char *interface,
                const char *property,
                sd_bus_message *reply,
                void *userdata,
                sd_bus_error *error) {

        ExecContext *c = userdata;

        assert(bus);
        assert(reply);
        assert(c);

        return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
}


static int acquire_path(const char *path, int flags, mode_t mode) {
        union sockaddr_union sa = {};
        _cleanup_close_ int fd = -1;
        int r, salen;

        assert(path);

        if (IN_SET(flags & O_ACCMODE, O_WRONLY, O_RDWR))
                flags |= O_CREAT;

        fd = open(path, flags|O_NOCTTY, mode);
        if (fd >= 0)
                return TAKE_FD(fd);

        if (errno != ENXIO) /* ENXIO is returned when we try to open() an AF_UNIX file system socket on Linux */
                return -errno;
        if (strlen(path) >= sizeof(sa.un.sun_path)) /* Too long, can't be a UNIX socket */
                return -ENXIO;

        /* So, it appears the specified path could be an AF_UNIX socket. Let's see if we can connect to it. */

        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0)
                return -errno;

        salen = sockaddr_un_set_path(&sa.un, path);
        if (salen < 0)
                return salen;

        if (connect(fd, &sa.sa, salen) < 0)
                return errno == EINVAL ? -ENXIO : -errno; /* Propagate initial error if we get EINVAL, i.e. we have
                                                           * indication that his wasn't an AF_UNIX socket after all */

        if ((flags & O_ACCMODE) == O_RDONLY)
                r = shutdown(fd, SHUT_WR);
        else if ((flags & O_ACCMODE) == O_WRONLY)
                r = shutdown(fd, SHUT_RD);
        else
                return TAKE_FD(fd);
        if (r < 0)
                return -errno;

        return TAKE_FD(fd);
}


static int property_get_stdio_fdname(
                sd_bus *bus,
                const char *path,
                const char *interface,
                const char *property,
                sd_bus_message *reply,
                void *userdata,
                sd_bus_error *error) {

        ExecContext *c = userdata;
        int fileno;

        assert(bus);
        assert(c);
        assert(property);
        assert(reply);

        if (streq(property, "StandardInputFileDescriptorName"))
                fileno = STDIN_FILENO;
        else if (streq(property, "StandardOutputFileDescriptorName"))
                fileno = STDOUT_FILENO;
        else {
                assert(streq(property, "StandardErrorFileDescriptorName"));
                fileno = STDERR_FILENO;
        }

        return sd_bus_message_append(reply, "s", exec_context_fdname(c, fileno));
}


static int assess_system_call_filter(
                const struct security_assessor *a,
                const struct security_info *info,
                const void *data,
                uint64_t *ret_badness,
                char **ret_description) {

        const SyscallFilterSet *f;
        char *d = NULL;
        uint64_t b;

        assert(a);
        assert(info);
        assert(ret_badness);
        assert(ret_description);

        assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
        f = syscall_filter_sets + a->parameter;

        if (!info->system_call_filter_whitelist && set_isempty(info->system_call_filter)) {
                d = strdup("Service does not filter system calls");
                b = 10;
        } else {
                bool bad;

                log_debug("Analyzing system call filter, checking against: %s", f->name);
                bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_whitelist, f);
                log_debug("Result: %s", bad ? "bad" : "good");

                if (info->system_call_filter_whitelist) {
                        if (bad) {
                                (void) asprintf(&d, "System call whitelist defined for service, and %s is included", f->name);
                                b = 9;
                        } else {
                                (void) asprintf(&d, "System call whitelist defined for service, and %s is not included", f->name);
                                b = 0;
                        }
                } else {
                        if (bad) {
                                (void) asprintf(&d, "System call blacklist defined for service, and %s is not included", f->name);
                                b = 10;
                        } else {
                                (void) asprintf(&d, "System call blacklist defined for service, and %s is included", f->name);
                                b = 5;
                        }
                }
        }

        if (!d)
                return log_oom();

        *ret_badness = b;
        *ret_description = d;

        return 0;
}


static int assess_user(
                const struct security_assessor *a,
                const struct security_info *info,
                const void *data,
                uint64_t *ret_badness,
                char **ret_description) {

        _cleanup_free_ char *d = NULL;
        uint64_t b;

        assert(ret_badness);
        assert(ret_description);

        if (streq_ptr(info->user, NOBODY_USER_NAME)) {
                d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
                b = 9;
        } else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
                d = strdup("Service runs under a transient non-root user identity");
                b = 0;
        } else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
                d = strdup("Service runs under a static non-root user identity");
                b = 0;
        } else {
                *ret_badness = 10;
                *ret_description = NULL;
                return 0;
        }

        if (!d)
                return log_oom();

        *ret_badness = b;
        *ret_description = TAKE_PTR(d);

        return 0;
}


static int property_read_restrict_address_families(
                sd_bus *bus,
                const char *member,
                sd_bus_message *m,
                sd_bus_error *error,
                void *userdata) {

        struct security_info *info = userdata;
        int whitelist, r;

        assert(bus);
        assert(member);
        assert(m);

        r = sd_bus_message_enter_container(m, 'r', "bas");
        if (r < 0)
                return r;

        r = sd_bus_message_read(m, "b", &whitelist);
        if (r < 0)
                return r;

        info->restrict_address_family_inet =
                info->restrict_address_family_unix =
                info->restrict_address_family_netlink =
                info->restrict_address_family_packet =
                info->restrict_address_family_other = whitelist;

        r = sd_bus_message_enter_container(m, 'a', "s");
        if (r < 0)
                return r;

        for (;;) {
                const char *name;

                r = sd_bus_message_read(m, "s", &name);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
                        info->restrict_address_family_inet = !whitelist;
                else if (streq(name, "AF_UNIX"))
                        info->restrict_address_family_unix = !whitelist;
                else if (streq(name, "AF_NETLINK"))
                        info->restrict_address_family_netlink = !whitelist;
                else if (streq(name, "AF_PACKET"))
                        info->restrict_address_family_packet = !whitelist;
                else
                        info->restrict_address_family_other = !whitelist;
        }

        r = sd_bus_message_exit_container(m);
        if (r < 0)
                return r;

        return sd_bus_message_exit_container(m);
}


static void unit_update_on_console(Unit *u) {
        bool b;

        assert(u);

        b = unit_needs_console(u);
        if (u->on_console == b)
                return;

        u->on_console = b;
        if (b)
                manager_ref_console(u->manager);
        else
                manager_unref_console(u->manager);
}


static int unit_export_invocation_id(Unit *u) {
        const char *p;
        int r;

        assert(u);

        if (u->exported_invocation_id)
                return 0;

        if (sd_id128_is_null(u->invocation_id))
                return 0;

        p = strjoina("/run/systemd/units/invocation:", u->id);
        r = symlink_atomic(u->invocation_id_string, p);
        if (r < 0)
                return log_unit_debug_errno(u, r, "Failed to create invocation ID symlink %s: %m", p);

        u->exported_invocation_id = true;
        return 0;
}


static bool unit_verify_deps(Unit *u) {
        Unit *other;
        Iterator j;
        void *v;

        assert(u);

        /* Checks whether all BindsTo= dependencies of this unit are fulfilled — if they are also combined with
         * After=. We do not check Requires= or Requisite= here as they only should have an effect on the job
         * processing, but do not have any effect afterwards. We don't check BindsTo= dependencies that are not used in
         * conjunction with After= as for them any such check would make things entirely racy. */

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], j) {

                if (!hashmap_contains(u->dependencies[UNIT_AFTER], other))
                        continue;

                if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(other))) {
                        log_unit_notice(u, "Bound to unit %s, but unit isn't active.", other->id);
                        return false;
                }
        }

        return true;
}


static int log_kill(pid_t pid, int sig, void *userdata) {
        _cleanup_free_ char *comm = NULL;

        (void) get_process_comm(pid, &comm);

        /* Don't log about processes marked with brackets, under the assumption that these are temporary processes
           only, like for example systemd's own PAM stub process. */
        if (comm && comm[0] == '(')
                return 0;

        log_unit_notice(userdata,
                        "Killing process " PID_FMT " (%s) with signal SIG%s.",
                        pid,
                        strna(comm),
                        signal_to_string(sig));

        return 1;
}


bool unit_can_stop(Unit *u) {
        assert(u);

        if (!unit_supported(u))
                return false;

        if (u->perpetual)
                return false;

        return !!UNIT_VTABLE(u)->stop;
}


int unit_ref_gid(Unit *u, gid_t gid, bool clean_ipc) {
        return unit_ref_uid_internal(u, (uid_t*) &u->ref_gid, (uid_t) gid, clean_ipc, manager_ref_gid);
}


void unit_log_process_exit(
                Unit *u,
                int level,
                const char *kind,
                const char *command,
                int code,
                int status) {

        assert(u);
        assert(kind);

        if (code != CLD_EXITED)
                level = LOG_WARNING;

        log_struct(level,
                   "MESSAGE_ID=" SD_MESSAGE_UNIT_PROCESS_EXIT_STR,
                   LOG_UNIT_MESSAGE(u, "%s exited, code=%s, status=%i/%s",
                                    kind,
                                    sigchld_code_to_string(code), status,
                                    strna(code == CLD_EXITED
                                          ? exit_status_to_string(status, EXIT_STATUS_FULL)
                                          : signal_to_string(status))),
                   "EXIT_CODE=%s", sigchld_code_to_string(code),
                   "EXIT_STATUS=%i", status,
                   "COMMAND=%s", strna(command),
                   LOG_UNIT_ID(u),
                   LOG_UNIT_INVOCATION_ID(u));
}


void unit_unwatch_bus_name(Unit *u, const char *name) {
        assert(u);
        assert(name);

        (void) hashmap_remove_value(u->manager->watch_bus, name, u);
        u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
}


static int set_complete_move(Set **s, Set **other) {
        assert(s);
        assert(other);

        if (!other)
                return 0;

        if (*s)
                return set_move(*s, *other);
        else
                *s = TAKE_PTR(*other);

        return 0;
}


static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
        const struct {
                UnitDependencyMask mask;
                const char *name;
        } table[] = {
                { UNIT_DEPENDENCY_FILE,               "file"               },
                { UNIT_DEPENDENCY_IMPLICIT,           "implicit"           },
                { UNIT_DEPENDENCY_DEFAULT,            "default"            },
                { UNIT_DEPENDENCY_UDEV,               "udev"               },
                { UNIT_DEPENDENCY_PATH,               "path"               },
                { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
                { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT,  "mountinfo-default"  },
                { UNIT_DEPENDENCY_PROC_SWAP,          "proc-swap"          },
        };
        size_t i;

        assert(f);
        assert(kind);
        assert(space);

        for (i = 0; i < ELEMENTSOF(table); i++) {

                if (mask == 0)
                        break;

                if (FLAGS_SET(mask, table[i].mask)) {
                        if (*space)
                                fputc(' ', f);
                        else
                                *space = true;

                        fputs(kind, f);
                        fputs("-", f);
                        fputs(table[i].name, f);

                        mask &= ~table[i].mask;
                }
        }

        assert(mask == 0);
}


static int unit_export_log_level_max(Unit *u, const ExecContext *c) {
        const char *p;
        char buf[2];
        int r;

        assert(u);
        assert(c);

        if (u->exported_log_level_max)
                return 0;

        if (c->log_level_max < 0)
                return 0;

        assert(c->log_level_max <= 7);

        buf[0] = '0' + c->log_level_max;
        buf[1] = 0;

        p = strjoina("/run/systemd/units/log-level-max:", u->id);
        r = symlink_atomic(buf, p);
        if (r < 0)
                return log_unit_debug_errno(u, r, "Failed to create maximum log level symlink %s: %m", p);

        u->exported_log_level_max = true;
        return 0;
}


static int unit_ref_uid_internal(
                Unit *u,
                uid_t *ref_uid,
                uid_t uid,
                bool clean_ipc,
                int (*_manager_ref_uid)(Manager *m, uid_t uid, bool clean_ipc)) {

        int r;

        assert(u);
        assert(ref_uid);
        assert(uid_is_valid(uid));
        assert(_manager_ref_uid);

        /* Generic implementation of both unit_ref_uid() and unit_ref_guid(), under the assumption that uid_t and gid_t
         * are actually the same type, and have the same validity rules.
         *
         * Adds a reference on a specific UID/GID to this unit. Each unit referencing the same UID/GID maintains a
         * reference so that we can destroy the UID/GID's IPC resources as soon as this is requested and the counter
         * drops to zero. */

        assert_cc(sizeof(uid_t) == sizeof(gid_t));
        assert_cc(UID_INVALID == (uid_t) GID_INVALID);

        if (*ref_uid == uid)
                return 0;

        if (uid_is_valid(*ref_uid)) /* Already set? */
                return -EBUSY;

        r = _manager_ref_uid(u->manager, uid, clean_ipc);
        if (r < 0)
                return r;

        *ref_uid = uid;
        return 1;
}


static int user_from_unit_name(Unit *u, char **ret) {

        static const uint8_t hash_key[] = {
                0x58, 0x1a, 0xaf, 0xe6, 0x28, 0x58, 0x4e, 0x96,
                0xb4, 0x4e, 0xf5, 0x3b, 0x8c, 0x92, 0x07, 0xec
        };

        _cleanup_free_ char *n = NULL;
        int r;

        r = unit_name_to_prefix(u->id, &n);
        if (r < 0)
                return r;

        if (valid_user_group_name(n)) {
                *ret = TAKE_PTR(n);
                return 0;
        }

        /* If we can't use the unit name as a user name, then let's hash it and use that */
        if (asprintf(ret, "_du%016" PRIx64, siphash24(n, strlen(n), hash_key)) < 0)
                return -ENOMEM;

        return 0;
}


void unit_dequeue_rewatch_pids(Unit *u) {
        int r;
        assert(u);

        if (!u->rewatch_pids_event_source)
                return;

        r = sd_event_source_set_enabled(u->rewatch_pids_event_source, SD_EVENT_OFF);
        if (r < 0)
                log_warning_errno(r, "Failed to disable event source for tidying watched PIDs, ignoring: %m");

        u->rewatch_pids_event_source = sd_event_source_unref(u->rewatch_pids_event_source);
}


void unit_add_to_dbus_queue(Unit *u) {
        assert(u);
        assert(u->type != _UNIT_TYPE_INVALID);

        if (u->load_state == UNIT_STUB || u->in_dbus_queue)
                return;

        /* Shortcut things if nobody cares */
        if (sd_bus_track_count(u->manager->subscribed) <= 0 &&
            sd_bus_track_count(u->bus_track) <= 0 &&
            set_isempty(u->manager->private_buses)) {
                u->sent_dbus_new_signal = true;
                return;
        }

        LIST_PREPEND(dbus_queue, u->manager->dbus_unit_queue, u);
        u->in_dbus_queue = true;
}


static void retroactively_start_dependencies(Unit *u) {
        Iterator i;
        Unit *other;
        void *v;

        assert(u);
        assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
                if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
                if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
                if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL, NULL);

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);

        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
}


static void _xmlrpc_charHandler(void *userData,
                        const char *s,
                        int len)
{
   xml_elem_data* mydata = (xml_elem_data*)userData;
   if(mydata && mydata->current) {

      /* Check if we need to decode utf-8 parser output to another encoding */
      if(mydata->needs_enc_conversion && mydata->input_options->encoding) {
         int new_len = 0;
         char* add_text = utf8_decode(s, len, &new_len, mydata->input_options->encoding);
         if(add_text) {
            len = new_len;
            simplestring_addn(&mydata->current->text, add_text, len);
            free(add_text);
            return;
         }
      }
      simplestring_addn(&mydata->current->text, s, len);
   }
}


void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
{
   xml_element_serialize(el, file_out_fptr, (void *)output, options, 0);
}


bitset_on_num(BitSetRef bs)
{
  int i, n;

  n = 0;
  for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
    if (BITSET_AT(bs, i)) n++;
  }
  return n;
}


compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
{
  int len, mod_tlen, cklen;
  int ckn;
  int infinite = IS_REPEAT_INFINITE(qn->upper);
  int empty_info = qn->target_empty_info;
  int tlen = compile_length_tree(qn->target, reg);

  if (tlen < 0) return tlen;

  ckn = ((reg->num_comb_exp_check > 0) ? qn->comb_exp_check_num : 0);

  cklen = (CKN_ON ? SIZE_STATE_CHECK_NUM: 0);

  /* anychar repeat */
  if (NTYPE(qn->target) == NT_CANY) {
    if (qn->greedy && infinite) {
      if (IS_NOT_NULL(qn->next_head_exact) && !CKN_ON)
        return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower + cklen;
      else
        return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower + cklen;
    }
  }

  if (empty_info != 0)
    mod_tlen = tlen + (SIZE_OP_NULL_CHECK_START + SIZE_OP_NULL_CHECK_END);
  else
    mod_tlen = tlen;

  if (infinite && qn->lower <= 1) {
    if (qn->greedy) {
      if (qn->lower == 1)
	len = SIZE_OP_JUMP;
      else
	len = 0;

      len += SIZE_OP_PUSH + cklen + mod_tlen + SIZE_OP_JUMP;
    }
    else {
      if (qn->lower == 0)
	len = SIZE_OP_JUMP;
      else
	len = 0;

      len += mod_tlen + SIZE_OP_PUSH + cklen;
    }
  }
  else if (qn->upper == 0) {
    if (qn->is_refered != 0) /* /(?<n>..){0}/ */
      len = SIZE_OP_JUMP + tlen;
    else
      len = 0;
  }
  else if (qn->upper == 1 && qn->greedy) {
    if (qn->lower == 0) {
      if (CKN_ON) {
	len = SIZE_OP_STATE_CHECK_PUSH + tlen;
      }
      else {
	len = SIZE_OP_PUSH + tlen;
      }
    }
    else {
      len = tlen;
    }
  }
  else if (!qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
    len = SIZE_OP_PUSH + cklen + SIZE_OP_JUMP + tlen;
  }
  else {
    len = SIZE_OP_REPEAT_INC
        + mod_tlen + SIZE_OPCODE + SIZE_RELADDR + SIZE_MEMNUM;
    if (CKN_ON)
      len += SIZE_OP_STATE_CHECK;
  }

  return len;
}


set_sub_anchor(regex_t* reg, OptAncInfo* anc)
{
  reg->sub_anchor |= anc->left_anchor  & ANCHOR_BEGIN_LINE;
  reg->sub_anchor |= anc->right_anchor & ANCHOR_END_LINE;
}


expand_case_fold_make_rem_string(Node** rnode, UChar *s, UChar *end,
				 regex_t* reg)
{
  int r;
  Node *node;

  node = onig_node_new_str(s, end);
  if (IS_NULL(node)) return ONIGERR_MEMORY;

  r = update_string_node_case_fold(reg, node);
  if (r != 0) {
    onig_node_free(node);
    return r;
  }

  NSTRING_SET_AMBIG(node);
  NSTRING_SET_DONT_GET_OPT_INFO(node);
  *rnode = node;
  return 0;
}


onig_chain_reduce(regex_t* reg)
{
  regex_t *head, *prev;

  prev = reg;
  head = prev->chain;
  if (IS_NOT_NULL(head)) {
    reg->state = ONIG_STATE_MODIFY;
    while (IS_NOT_NULL(head->chain)) {
      prev = head;
      head = head->chain;
    }
    prev->chain = (regex_t* )NULL;
    REGEX_TRANSFER(reg, head);
  }
}


next_setup(Node* node, Node* next_node, regex_t* reg)
{
  int type;

 retry:
  type = NTYPE(node);
  if (type == NT_QTFR) {
    QtfrNode* qn = NQTFR(node);
    if (qn->greedy && IS_REPEAT_INFINITE(qn->upper)) {
#ifdef USE_QTFR_PEEK_NEXT
      Node* n = get_head_value_node(next_node, 1, reg);
      /* '\0': for UTF-16BE etc... */
      if (IS_NOT_NULL(n) && NSTR(n)->s[0] != '\0') {
	qn->next_head_exact = n;
      }
#endif
      /* automatic posseivation a*b ==> (?>a*)b */
      if (qn->lower <= 1) {
	int ttype = NTYPE(qn->target);
	if (IS_NODE_TYPE_SIMPLE(ttype)) {
	  Node *x, *y;
	  x = get_head_value_node(qn->target, 0, reg);
	  if (IS_NOT_NULL(x)) {
	    y = get_head_value_node(next_node,  0, reg);
	    if (IS_NOT_NULL(y) && is_not_included(x, y, reg)) {
	      Node* en = onig_node_new_enclose(ENCLOSE_STOP_BACKTRACK);
	      CHECK_NULL_RETURN_MEMERR(en);
	      SET_ENCLOSE_STATUS(en, NST_STOP_BT_SIMPLE_REPEAT);
	      swap_node(node, en);
	      NENCLOSE(node)->target = en;
	    }
	  }
	}
      }
    }
  }
  else if (type == NT_ENCLOSE) {
    EncloseNode* en = NENCLOSE(node);
    if (en->type == ENCLOSE_MEMORY) {
      node = en->target;
      goto retry;
    }
  }
  return 0;
}


is_full_opt_exact_info(OptExactInfo* ex)
{
  return (ex->len >= OPT_EXACT_MAXLEN ? 1 : 0);
}


clear_opt_anc_info(OptAncInfo* anc)
{
  anc->left_anchor  = 0;
  anc->right_anchor = 0;
}


alt_merge_opt_map_info(OnigEncoding enc, OptMapInfo* to, OptMapInfo* add)
{
  int i, val;

  /* if (! is_equal_mml(&to->mmd, &add->mmd)) return ; */
  if (to->value == 0) return ;
  if (add->value == 0 || to->mmd.max < add->mmd.min) {
    clear_opt_map_info(to);
    return ;
  }

  alt_merge_mml(&to->mmd, &add->mmd);

  val = 0;
  for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) {
    if (add->map[i])
      to->map[i] = 1;

    if (to->map[i])
      val += map_position_value(enc, i);
  }
  to->value = val;

  alt_merge_opt_anc_info(&to->anc, &add->anc);
}


quantifiers_memory_node_info(Node* node)
{
  int r = 0;

  switch (NTYPE(node)) {
  case NT_LIST:
  case NT_ALT:
    {
      int v;
      do {
	v = quantifiers_memory_node_info(NCAR(node));
	if (v > r) r = v;
      } while (v >= 0 && IS_NOT_NULL(node = NCDR(node)));
    }
    break;

#ifdef USE_SUBEXP_CALL
  case NT_CALL:
    if (IS_CALL_RECURSION(NCALL(node))) {
      return NQ_TARGET_IS_EMPTY_REC; /* tiny version */
    }
    else
      r = quantifiers_memory_node_info(NCALL(node)->target);
    break;
#endif

  case NT_QTFR:
    {
      QtfrNode* qn = NQTFR(node);
      if (qn->upper != 0) {
	r = quantifiers_memory_node_info(qn->target);
      }
    }
    break;

  case NT_ENCLOSE:
    {
      EncloseNode* en = NENCLOSE(node);
      switch (en->type) {
      case ENCLOSE_MEMORY:
	return NQ_TARGET_IS_EMPTY_MEM;
	break;

      case ENCLOSE_OPTION:
      case ENCLOSE_STOP_BACKTRACK:
	r = quantifiers_memory_node_info(en->target);
	break;
      default:
	break;
      }
    }
    break;

  case NT_BREF:
  case NT_STR:
  case NT_CTYPE:
  case NT_CCLASS:
  case NT_CANY:
  case NT_ANCHOR:
  default:
    break;
  }

  return r;
}


distance_add(OnigDistance d1, OnigDistance d2)
{
  if (d1 == ONIG_INFINITE_DISTANCE || d2 == ONIG_INFINITE_DISTANCE)
    return ONIG_INFINITE_DISTANCE;
  else {
    if (d1 <= ONIG_INFINITE_DISTANCE - d2) return d1 + d2;
    else return ONIG_INFINITE_DISTANCE;
  }
}


check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask)
{
  int type, r = 0;

  type = NTYPE(node);
  if ((NTYPE2BIT(type) & type_mask) == 0)
    return 1;

  switch (type) {
  case NT_LIST:
  case NT_ALT:
    do {
      r = check_type_tree(NCAR(node), type_mask, enclose_mask,
			  anchor_mask);
    } while (r == 0 && IS_NOT_NULL(node = NCDR(node)));
    break;

  case NT_QTFR:
    r = check_type_tree(NQTFR(node)->target, type_mask, enclose_mask,
			anchor_mask);
    break;

  case NT_ENCLOSE:
    {
      EncloseNode* en = NENCLOSE(node);
      if ((en->type & enclose_mask) == 0)
	return 1;

      r = check_type_tree(en->target, type_mask, enclose_mask, anchor_mask);
    }
    break;

  case NT_ANCHOR:
    type = NANCHOR(node)->type;
    if ((type & anchor_mask) == 0)
      return 1;

    if (NANCHOR(node)->target)
      r = check_type_tree(NANCHOR(node)->target,
			  type_mask, enclose_mask, anchor_mask);
    break;

  default:
    break;
  }
  return r;
}


extern void onig_add_end_call(void (*func)(void))
{
  OnigEndCallListItemType* item;

  item = (OnigEndCallListItemType* )xmalloc(sizeof(*item));
  if (item == 0) return ;

  item->next = EndCallTop;
  item->func = func;

  EndCallTop = item;
}


utf32le_mbc_case_fold(OnigCaseFoldType flag,
		      const UChar** pp, const UChar* end, UChar* fold)
{
  const UChar* p = *pp;

  if (ONIGENC_IS_ASCII_CODE(*p) && *(p+1) == 0 && *(p+2) == 0 && *(p+3) == 0) {
#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
    if ((flag & ONIGENC_CASE_FOLD_TURKISH_AZERI) != 0) {
      if (*p == 0x49) {
	*fold++ = 0x31;
	*fold++ = 0x01;
      }
    }
    else {
#endif
      *fold++ = ONIGENC_ASCII_CODE_TO_LOWER_CASE(*p);
      *fold++ = 0;
#ifdef USE_UNICODE_CASE_FOLD_TURKISH_AZERI
    }
#endif

    *fold++ = 0;
    *fold   = 0;
    *pp += 4;
    return 4;
  }
  else
    return onigenc_unicode_mbc_case_fold(ONIG_ENCODING_UTF32_LE, flag, pp, end,
					 fold);
}


utf16le_mbc_enc_len(const UChar* p)
{
  return EncLen_UTF16[*(p+1)];
}


utf32be_code_to_mbclen(OnigCodePoint code ARG_UNUSED)
{
  return 4;
}


utf32be_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED)
{
  if (end - p < 4) return 0;
  return (OnigCodePoint )(((p[0] * 256 + p[1]) * 256 + p[2]) * 256 + p[3]);
}


utf16le_is_mbc_newline(const UChar* p, const UChar* end)
{
  if (p + 1 < end) {
    if (*p == 0x0a && *(p+1) == 0x00)
      return 1;
#ifdef USE_UNICODE_ALL_LINE_TERMINATORS
    if ((
#ifndef USE_CRNL_AS_LINE_TERMINATOR
         *p == 0x0d ||
#endif
         *p == 0x85) && *(p+1) == 0x00)
      return 1;

    if (*(p+1) == 0x20 && (*p == 0x29 || *p == 0x28))
      return 1;
#endif
  }
  return 0;
}


init(void)
{
#ifdef USE_CALLOUT

    int id;
    OnigEncoding enc;
    char* name;
    unsigned int args[4];
    OnigValue opts[4];

    enc = ONIG_ENCODING_UTF16_BE;

    name = "\000F\000A\000I\000L\000\000";            BC0_P(name, fail);
    name = "\000M\000I\000S\000M\000A\000T\000C\000H\000\000"; BC0_P(name, mismatch);

    name = "\000M\000A\000X\000\000";
    args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
    args[1] = ONIG_TYPE_CHAR;
    opts[0].c = 'X';
    BC_B_O(name, max, 2, args, 1, opts);

    name = "\000E\000R\000R\000O\000R\000\000";
    args[0] = ONIG_TYPE_LONG; opts[0].l = ONIG_ABORT;
    BC_P_O(name, error, 1, args, 1, opts);

    name = "\000C\000O\000U\000N\000T\000\000";
    args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
    BC_B_O(name, count, 1, args, 1, opts);

    name = "\000T\000O\000T\000A\000L\000_\000C\000O\000U\000N\000T\000\000";
    args[0] = ONIG_TYPE_CHAR; opts[0].c = '>';
    BC_B_O(name, total_count, 1, args, 1, opts);

    name = "\000C\000M\000P\000\000";
    args[0] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
    args[1] = ONIG_TYPE_STRING;
    args[2] = ONIG_TYPE_TAG | ONIG_TYPE_LONG;
    BC_P(name, cmp, 3, args);

#endif /* USE_CALLOUT */

  return ONIG_NORMAL;
}


void buffer_new(struct buffer_st *b)
{
  b->length = 512;
  b->data = emalloc(sizeof(char)*(b->length));
  b->data[0] = 0;
  b->ptr = b->data;
  b->offset = 0;
}


void buffer_delete(struct buffer_st *b)
{
  efree(b->data);
  b->length = 0;
  b->offset = 0;
  b->ptr = NULL;
  b->data = NULL;
}


static OnigEncoding _php_mb_regex_name2mbctype(const char *pname)
{
	const char *p;
	const php_mb_regex_enc_name_map_t *mapping;

	if (pname == NULL || !*pname) {
		return ONIG_ENCODING_UNDEF;
	}

	for (mapping = enc_name_map; mapping->names != NULL; mapping++) {
		for (p = mapping->names; *p != '\0'; p += (strlen(p) + 1)) {
			if (strcasecmp(p, pname) == 0) {
				return mapping->code;
			}
		}
	}

	return ONIG_ENCODING_UNDEF;
}


_php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
	char *arg_pattern = NULL, *arg_options = NULL;
	size_t arg_pattern_len, arg_options_len;
	int err;
	size_t n, i, pos, len, beg, end;
	OnigOptionType option;
	OnigUChar *str;
	OnigSyntaxType *syntax;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ss", &arg_pattern, &arg_pattern_len, &arg_options, &arg_options_len) == FAILURE) {
		return;
	}

	option = MBREX(regex_default_options);

	if (arg_options) {
		option = 0;
		_php_mb_regex_init_options(arg_options, arg_options_len, &option, &syntax, NULL);
	}

	if (arg_pattern) {
		/* create regex pattern buffer */
		if ((MBREX(search_re) = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, option, MBREX(current_mbctype), MBREX(regex_default_syntax))) == NULL) {
			RETURN_FALSE;
		}
	}

	pos = MBREX(search_pos);
	str = NULL;
	len = 0;
	if (!Z_ISUNDEF(MBREX(search_str)) && Z_TYPE(MBREX(search_str)) == IS_STRING){
		str = (OnigUChar *)Z_STRVAL(MBREX(search_str));
		len = Z_STRLEN(MBREX(search_str));
	}

	if (MBREX(search_re) == NULL) {
		php_error_docref(NULL, E_WARNING, "No regex given");
		RETURN_FALSE;
	}

	if (str == NULL) {
		php_error_docref(NULL, E_WARNING, "No string given");
		RETURN_FALSE;
	}

	if (MBREX(search_regs)) {
		onig_region_free(MBREX(search_regs), 1);
	}
	MBREX(search_regs) = onig_region_new();

	err = onig_search(MBREX(search_re), str, str + len, str + pos, str  + len, MBREX(search_regs), 0);
	if (err == ONIG_MISMATCH) {
		MBREX(search_pos) = len;
		RETVAL_FALSE;
	} else if (err <= -2) {
		OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
		onig_error_code_to_str(err_str, err);
		php_error_docref(NULL, E_WARNING, "mbregex search failure in mbregex_search(): %s", err_str);
		RETVAL_FALSE;
	} else {
		switch (mode) {
		case 1:
			array_init(return_value);
			beg = MBREX(search_regs)->beg[0];
			end = MBREX(search_regs)->end[0];
			add_next_index_long(return_value, beg);
			add_next_index_long(return_value, end - beg);
			break;
		case 2:
			array_init(return_value);
			n = MBREX(search_regs)->num_regs;
			for (i = 0; i < n; i++) {
				beg = MBREX(search_regs)->beg[i];
				end = MBREX(search_regs)->end[i];
				if (beg >= 0 && beg <= end && end <= len) {
					add_index_stringl(return_value, i, (char *)&str[beg], end - beg);
				} else {
					add_index_bool(return_value, i, 0);
				}
			}
			if (onig_number_of_names(MBREX(search_re)) > 0) {
				mb_regex_groups_iter_args args = {
					return_value,
					Z_STRVAL(MBREX(search_str)),
					Z_STRLEN(MBREX(search_str)),
					MBREX(search_regs)
				};
				onig_foreach_name(MBREX(search_re), mb_regex_groups_iter, &args);
			}
			break;
		default:
			RETVAL_TRUE;
			break;
		}
		end = MBREX(search_regs)->end[0];
		if (pos <= end) {
			MBREX(search_pos) = end;
		} else {
			MBREX(search_pos) = pos + 1;
		}
	}

	if (err < 0) {
		onig_region_free(MBREX(search_regs), 1);
		MBREX(search_regs) = (OnigRegion *)NULL;
	}
}


zend_mb_regex_globals *php_mb_regex_globals_alloc(void)
{
	zend_mb_regex_globals *pglobals = pemalloc(
			sizeof(zend_mb_regex_globals), 1);
	if (SUCCESS != _php_mb_regex_globals_ctor(pglobals)) {
		pefree(pglobals, 1);
		return NULL;
	}
	return pglobals;
}


static const char *_php_mb_regex_mbctype2name(OnigEncoding mbctype)
{
	const php_mb_regex_enc_name_map_t *mapping;

	for (mapping = enc_name_map; mapping->names != NULL; mapping++) {
		if (mapping->code == mbctype) {
			return mapping->names;
		}
	}

	return NULL;
}


PHP_FUNCTION(gethostname)
{
	char buf[HOST_NAME_MAX + 1];

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	if (gethostname(buf, sizeof(buf))) {
		php_error_docref(NULL, E_WARNING, "unable to fetch host [%d]: %s", errno, strerror(errno));
		RETURN_FALSE;
	}

	RETURN_STRING(buf);
}


JVM_GetAllThreads(JNIEnv *env, jclass aClass)
{
	Trc_SC_GetAllThreads(env);
	exit(223);
}


removeSuffix(char *string, const char *suffix)
{
	size_t stringLength = strlen(string);
	size_t suffixLength = strlen(suffix);

	if (stringLength >= suffixLength) {
		char *tail = &string[stringLength - suffixLength];

		if (0 == strcmp(tail, suffix)) {
			*tail = '\0';
		}
	}
}


static char* jvmBufferData(J9StringBuffer* buffer) {
	return buffer ? buffer->data : NULL;
}


setZOSThrWeight(void)
{
	BOOLEAN success = FALSE;
	const UDATA jvmZOSTW = checkZOSThrWeightEnvVar();

	if (ZOS_THR_WEIGHT_NOT_FOUND != jvmZOSTW) {
		omrthread_t thandle = NULL;
		IDATA trc = 0;

		/* Attach so that we can use omrthread_global() below */
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
		trc = omrthread_attach_ex(&thandle, J9THREAD_ATTR_DEFAULT);
#else
		trc = f_threadAttachEx(&thandle, J9THREAD_ATTR_DEFAULT);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

		if (0 == trc) {
			UDATA * gtw = NULL;

#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
			gtw = omrthread_global("thread_weight");
#else
			gtw = f_threadGlobal("thread_weight");
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

			if (NULL != gtw) {
				if (ZOS_THR_WEIGHT_HEAVY == jvmZOSTW) {
					*gtw = (UDATA)"heavy";
				} else {
					*gtw = (UDATA)"medium";
				}
				success = TRUE;
			}

#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
			omrthread_detach(thandle);
#else
			f_threadDetach(thandle);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
		}
	} else {
		success = TRUE;
	}

	return success;
}


preloadLibraries(void)
{
	char* tempchar = 0;
	char jvmDLLName[J9_MAX_PATH];
	J9StringBuffer * jvmDLLNameBuffer = NULL;
	wchar_t unicodeDLLName[J9_MAX_PATH + 1] = {0}; /*extra character is added to check if path is truncated by GetModuleFileNameW()*/
	DWORD unicodeDLLNameLength = 0;
	UINT prevMode;
	HINSTANCE vmDLL = 0;
	HINSTANCE threadDLL = 0;
	HINSTANCE portDLL = 0;
	char* vmDllName = J9_VM_DLL_NAME;
	char* vmName = NULL;
	static beenRun=FALSE;
	if(beenRun) {
		return TRUE;
	}
	beenRun = TRUE;

	unicodeDLLNameLength = GetModuleFileNameW(jvm_dllHandle, unicodeDLLName, (J9_MAX_PATH + 1));
	/* Don't use truncated path */
	if (unicodeDLLNameLength > (DWORD)J9_MAX_PATH) {
		fprintf(stderr,"ERROR: failed to load library. Path is too long: %ls\n", unicodeDLLName);
		return FALSE;
	}

	/* Use of jvmDLLName is safe as the length is passed in */
	WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeDLLName, -1,  jvmDLLName, J9_MAX_PATH, NULL, NULL);

	jvmDLLNameBuffer = jvmBufferCat(NULL, jvmDLLName);
	j9binBuffer = jvmBufferCat(j9binBuffer, jvmDLLName);

	/* detect if we're in a subdir or not - is the j9vm dll in the subdir? */
	truncatePath(jvmBufferData(jvmDLLNameBuffer));
	jvmDLLNameBuffer = jvmBufferCat(jvmDLLNameBuffer, "\\");
	jvmDLLNameBuffer = jvmBufferCat(jvmDLLNameBuffer, vmDllName);
	jvmDLLNameBuffer = jvmBufferCat(jvmDLLNameBuffer, ".dll");

	/* Last argument tells Windows the size of the buffer */
	MultiByteToWideChar(OS_ENCODING_CODE_PAGE, OS_ENCODING_MB_FLAGS, jvmBufferData(jvmDLLNameBuffer), -1, unicodeDLLName, J9_MAX_PATH);
	if(INVALID_FILE_ATTRIBUTES != GetFileAttributesW(unicodeDLLName)) {
		jvmInSubdir = TRUE;
	} else {
		jvmInSubdir = FALSE;
	}

	prevMode = SetErrorMode( SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS );

	free(jvmDLLNameBuffer);
	jvmDLLNameBuffer = NULL;
	free(jrebinBuffer);
	jrebinBuffer = NULL;

	if(jvmInSubdir) {
		/* truncate the \<my vm name>\jvm.dll from the string */
		truncatePath(jvmBufferData(j9binBuffer));
		jrebinBuffer = jvmBufferCat(NULL, jvmBufferData(j9binBuffer));
		truncatePath(jvmBufferData(jrebinBuffer));
	} else {
		/* in this config, j9binBuffer and jrebinBuffer point to the same place - jre/bin/ */
		truncatePath(jvmBufferData(j9binBuffer));
		truncatePath(jvmBufferData(j9binBuffer));
		jrebinBuffer = jvmBufferCat(NULL, jvmBufferData(j9binBuffer));
	}

	j9libBuffer = jvmBufferCat(NULL, jvmBufferData(jrebinBuffer));
	truncatePath(jvmBufferData(j9libBuffer));
	j9Buffer = jvmBufferCat(NULL, jvmBufferData(j9libBuffer));
	truncatePath(jvmBufferData(j9Buffer));
	j9libBuffer = jvmBufferCat(j9libBuffer, DIR_SEPARATOR_STR "lib");

	j9libvmBuffer = jvmBufferCat(NULL, jvmBufferData(j9libBuffer));
	/* append /<vm name> to j9libBuffer to get location of j9ddr.dat file */
	vmName = strrchr(jvmBufferData(j9binBuffer), DIR_SEPARATOR);
	if (NULL != vmName) {
		j9libvmBuffer = jvmBufferCat(j9libvmBuffer, vmName);
	}

	DBG_MSG(("j9binBuffer   = <%s>\n", jvmBufferData(j9binBuffer)));
	DBG_MSG(("jrebinBuffer  = <%s>\n", jvmBufferData(jrebinBuffer)));
	DBG_MSG(("j9libBuffer   = <%s>\n", jvmBufferData(j9libBuffer)));
	DBG_MSG(("j9libvmBuffer = <%s>\n", jvmBufferData(j9libvmBuffer)));
	DBG_MSG(("j9Buffer      = <%s>\n", jvmBufferData(j9Buffer)));

#if !CALL_BUNDLED_FUNCTIONS_DIRECTLY
	vmDLL = (HINSTANCE) preloadLibrary(vmDllName, TRUE);
	preloadLibrary(J9_HOOKABLE_DLL_NAME, TRUE);

	SetErrorMode( prevMode );

	if (vmDLL < (HINSTANCE)HINSTANCE_ERROR) {
		fprintf(stderr,"jvm.dll failed to load: %s\n", vmDllName);
		return FALSE;
	}
	globalCreateVM = (CreateVM) GetProcAddress (vmDLL, (LPCSTR) CREATE_JAVA_VM_ENTRYPOINT );
	globalGetVMs = (GetVMs) GetProcAddress (vmDLL, (LPCSTR) GET_JAVA_VMS_ENTRYPOINT);
	if (!globalCreateVM || !globalGetVMs) {
		FreeLibrary(vmDLL);
		fprintf(stderr,"jvm.dll failed to load: global entrypoints not found\n");
		return FALSE;
	}
	j9vm_dllHandle = vmDLL;

	threadDLL = (HINSTANCE) preloadLibrary(J9_THREAD_DLL_NAME, TRUE);
	f_threadGlobal = (ThreadGlobal) GetProcAddress (threadDLL, (LPCSTR) "omrthread_global");
	f_threadAttachEx = (ThreadAttachEx) GetProcAddress (threadDLL, (LPCSTR) "omrthread_attach_ex");
	f_threadDetach = (ThreadDetach) GetProcAddress (threadDLL, (LPCSTR) "omrthread_detach");
	f_monitorEnter = (MonitorEnter) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_enter");
	f_monitorExit = (MonitorExit) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_exit");
	f_monitorInit = (MonitorInit) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_init_with_name");
	f_monitorDestroy = (MonitorDestroy) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_destroy");
	f_monitorWaitTimed = (MonitorWaitTimed) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_wait_timed");
	f_monitorNotify = (MonitorNotify) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_notify");
	f_monitorNotifyAll = (MonitorNotifyAll) GetProcAddress (threadDLL, (LPCSTR) "omrthread_monitor_notify_all");
	f_threadLibControl = (ThreadLibControl) GetProcAddress (threadDLL, (LPCSTR) "omrthread_lib_control");
	f_setCategory = (SetCategory) GetProcAddress (threadDLL, (LPCSTR) "omrthread_set_category");
	f_libEnableCPUMonitor = (LibEnableCPUMonitor) GetProcAddress (threadDLL, (LPCSTR) "omrthread_lib_enable_cpu_monitor");
	if (!f_threadGlobal || !f_threadAttachEx || !f_threadDetach || !f_monitorEnter || !f_monitorExit || !f_monitorInit || !f_monitorDestroy || !f_monitorWaitTimed
		|| !f_monitorNotify || !f_monitorNotifyAll || !f_threadLibControl || !f_setCategory || !f_libEnableCPUMonitor) {
		FreeLibrary(vmDLL);
		FreeLibrary(threadDLL);
		fprintf(stderr,"jvm.dll failed to load: thread library entrypoints not found\n");
		return FALSE;
	}

	/* pre-load port library for memorycheck */
	portDLL = (HINSTANCE) preloadLibrary(J9_PORT_DLL_NAME, TRUE);
	portInitLibrary = (PortInitLibrary) GetProcAddress (portDLL, (LPCSTR) "j9port_init_library");
	portGetSizeFn = (PortGetSize) GetProcAddress (portDLL, (LPCSTR) "j9port_getSize");
	portGetVersionFn = (PortGetVersion) GetProcAddress (portDLL, (LPCSTR) "j9port_getVersion");
	if (!portInitLibrary) {
		FreeLibrary(vmDLL);
		FreeLibrary(threadDLL);
		FreeLibrary(portDLL);
		fprintf(stderr,"jvm.dll failed to load: %s entrypoints not found\n", J9_PORT_DLL_NAME);
		return FALSE;
	}
	preloadLibrary(J9_ZIP_DLL_NAME, TRUE);

#ifdef J9_CLEAR_VM_INTERFACE_DLL_NAME
	/* CMVC 142575: Harmony JDWP sits apart for the JVM natives including the vmi.
	 * We must preload the library so that it can be found when JDWP tries to load it. */
	preloadLibrary(J9_CLEAR_VM_INTERFACE_DLL_NAME, TRUE);
#endif

#endif /* !CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	/* CMVC 152702: with other JVM on the path this library can get loaded from the wrong
	 * location if not preloaded. */
#ifdef J9VM_OPT_HARMONY
	preloadLibrary(J9_HARMONY_PORT_LIBRARY_SHIM_DLL_NAME, TRUE);
#endif /* J9VM_OPT_HARMONY */
	return TRUE;
}


JVM_Write(jint descriptor, const char* buffer, jint length)
{
	PORT_ACCESS_FROM_JAVAVM(BFUjavaVM);
	jint result = 0;

	Trc_SC_Write_Entry(descriptor, buffer, length);

	if (descriptor == -1) {
		Trc_SC_Write_bad_descriptor();
		return JVM_IO_ERR;
	}

#ifndef J9ZOS390
	/* This code SHOULD be for Windows only, but is safe everywhere except z/OS
	 * (see CMVC 99667 for the fun details of z/OS and POSIX File-handles):
	 * Map stdout, stderr to the port library as using the
	 * C library causes CR/LF translation and CR LF turns into CR CR LF.
	 */
	if ( (descriptor == 1) || (descriptor == 2) ) {
		IDATA retval = j9file_write(descriptor, (char *)buffer, length);
		if(retval<0) {
			result = -1;  /* callers seem to expect -1 on failure */
		} else {
			result = (jint)retval;
			Assert_SC_true(retval == (IDATA)result);
		}
	} else
#endif
	{
		/* CMVC 178203 - Restart system calls interrupted by EINTR */
		do {
			result = write(descriptor, buffer, length);
		} while ((-1 == result) && (EINTR == errno));
	}

	Trc_SC_Write_Exit(result);

	return result;
}


JVM_RegisterUnsafeMethods(JNIEnv* env, jclass unsafeClz)
{

	Trc_SC_RegisterUnsafeMethods(env);

}


addHarmonyPortLibrary(J9PortLibrary * portLib, J9JavaVMArgInfoList *vmArgumentsList, UDATA verboseFlags)
{
	JavaVMInitArgs dummyArgs = {0, 0, NULL, FALSE}; /* In this case, addHarmonyPortLibToVMArgs looks only at nOptions */
	J9JavaVMArgInfo *optArg = newJavaVMArgInfo(vmArgumentsList, NULL, CONSUMABLE_ARG);
	if (NULL == optArg) {
		return -1;
	}

	addHarmonyPortLibToVMArgs(portLib, &(optArg->vmOpt), &dummyArgs, &harmonyPortLibrary);
	return 0;
}


bfuThreadEnd(J9HookInterface** vmHooks, UDATA eventNum, void* eventData, void* userData)
{
	J9VMThread* vmThread = ((J9VMThreadDestroyEvent*)eventData)->vmThread;
	HANDLE event = (HANDLE) vmThread->sidecarEvent;

	if (event) {
		CloseHandle(event);
		vmThread->sidecarEvent = NULL;
	}
}


jint JNICALL JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *vm_args) {
	J9JavaVM *j9vm = NULL;
	jint result = JNI_OK;
	IDATA xoss = -1;
	IDATA ibmMallocTraceSet = FALSE;
 	char cwd[J9_MAX_PATH];
#ifdef WIN32
	wchar_t unicodeTemp[J9_MAX_PATH];
	char *altLibraryPathBuffer = NULL;
#endif /* WIN32 */
	UDATA argEncoding = ARG_ENCODING_DEFAULT;
	UDATA altJavaHomeSpecified = 0; /* not used on non-Windows */
	J9PortLibraryVersion portLibraryVersion;
	UDATA j2seVersion;
#if defined(AIXPPC)
	char *origLibpath = NULL;
#endif /* AIXPPC */
	I_32 portLibraryInitStatus;
	UDATA expectedLibrarySize;
	UDATA localVerboseLevel = 0;
	J9CreateJavaVMParams createParams = {0};
	JavaVMInitArgs *args = NULL;
	UDATA launcherArgumentsSize = 0;
	J9VMInitArgs *j9ArgList = NULL;
	char *xServiceBuffer = NULL;
	const char *libpathValue = NULL;
	const char *ldLibraryPathValue = NULL;
	J9SpecialArguments specialArgs;
	omrthread_t attachedThread = NULL;
	specialArgs.localVerboseLevel = localVerboseLevel;
	specialArgs.xoss = &xoss;
	specialArgs.argEncoding = &argEncoding;
	specialArgs.executableJarPath = NULL;
	specialArgs.ibmMallocTraceSet = &ibmMallocTraceSet;
#ifdef J9ZTPF

    result = tpf_eownrc(TPF_SET_EOWNR, "IBMRT4J                        ");

    if (result < 0)  {
        fprintf(stderr, "Failed to issue tpf_eownrc.");
        return JNI_ERR;
    }
    result = tmslc(TMSLC_ENABLE+TMSLC_HOLD, "IBMRT4J");
    if (result < 0)  {
        fprintf(stderr, "Failed to start time slicing.");
        return JNI_ERR;
    }
#endif /* defined(J9ZTPF) */
	/*
	 * Linux uses LD_LIBRARY_PATH
	 * z/OS uses LIBPATH
	 * AIX uses both
	 * use native OS calls because port library isn't ready.
	 * Copy the strings because the value returned by getenv may change.
	 */
#if defined(AIXPPC) || defined(J9ZOS390)
	libpathValue = getenv(ENV_LIBPATH);
	if (NULL != libpathValue) {
		size_t pathLength = strlen(libpathValue) +1;
		char *envTemp = malloc(pathLength);
		if (NULL == envTemp) {
			result = JNI_ERR;
			goto exit;
		}
		strcpy(envTemp, libpathValue);
		libpathValue = envTemp;
	}
#endif
#if defined(J9UNIX)
	ldLibraryPathValue = getenv(ENV_LD_LIB_PATH);
	if (NULL != ldLibraryPathValue) {
		size_t pathLength = strlen(ldLibraryPathValue) +1;
		char *envTemp = malloc(pathLength);
		if (NULL == envTemp) {
			result = JNI_ERR;
			goto exit;
		}
		strcpy(envTemp, ldLibraryPathValue);
		ldLibraryPathValue = envTemp;
	}
#endif /* defined(J9UNIX) */

	if (BFUjavaVM != NULL) {
		result = JNI_ERR;
		goto exit;
	}

#ifdef J9OS_I5
	/* debug code */
	Xj9BreakPoint("jvm");
	/* Force iSeries create JVM flow */
	if (Xj9IleCreateJavaVmCalled() == 0) {
	    result = Xj9CallIleCreateJavaVm(pvm, penv, vm_args);
	    goto exit;
	}
#endif

#if defined(AIXPPC)
	/* CMVC 137180:
	 * in some cases the LIBPATH does not contain /usr/lib, when
	 * trying to load application native libraries that are linked against
	 * libraries in /usr/lib we could fail to find those libraries if /usr/lib
	 * is not on the LIBPATH.
	 * */
	addToLibpath("/usr/lib", FALSE);
	/* CMVC 135358.
	 * This function modifies LIBPATH while dlopen()ing J9 shared libs.
	 * Save the original so that it can be restored at the end of the
	 * function.
	 */
	origLibpath = getenv("LIBPATH");
#endif

	/* no tracing for this function, since it's unlikely to be used once the VM is running and the trace engine is initialized */
	preloadLibraries();

#ifdef WIN32
	if (GetCurrentDirectoryW(J9_MAX_PATH, unicodeTemp) == 0) {
		strcpy(cwd, "\\");
	} else {
		WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeTemp, -1,  cwd, J9_MAX_PATH, NULL, NULL);
	}
#else
	if (getcwd(cwd, J9_MAX_PATH) == NULL) {
		strcpy(cwd, ".");
	}
#endif
#ifdef DEBUG
	printf("cwd = %s\n", cwd);
#endif

#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
	if (0 != omrthread_attach_ex(&attachedThread, J9THREAD_ATTR_DEFAULT)) {
		result = JNI_ERR;
	}
#else /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	if (0 != f_threadAttachEx(&attachedThread, J9THREAD_ATTR_DEFAULT)) {
		result = JNI_ERR;
	}
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	if (JNI_OK != result) {
		goto exit;
	}

#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
	omrthread_lib_enable_cpu_monitor(attachedThread);
#else /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	f_libEnableCPUMonitor(attachedThread);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

#if defined(J9ZOS390)
	/*
	 * When we init the port lib, the 'Signal Reporter' thread will be spawned.
	 * On z/OS, we need to know whether this thread should be spawned as a medium
	 * or heavy weight thread. We do this here but we will only take into
	 * account JAVA_THREAD_MODEL - i.e., if the customer is using '-Xthr:tw=heavy'
	 * instead of the env var, the 'Signal Reporter' thread will still be launched
	 * as a medium weight thread (see PR100512).
	 */
	if (!setZOSThrWeight()) {
		return JNI_ERR;
	}
#endif /* defined(J9ZOS390) */

	/* Use portlibrary version which we compiled against, and have allocated space
	 * for on the stack.  This version may be different from the one in the linked DLL.
	 */
	J9PORT_SET_VERSION(&portLibraryVersion, J9PORT_CAPABILITY_MASK);

	expectedLibrarySize = sizeof(J9PortLibrary);
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
	portLibraryInitStatus = j9port_init_library(&j9portLibrary, &portLibraryVersion, expectedLibrarySize);
#else
	portLibraryInitStatus = portInitLibrary(&j9portLibrary, &portLibraryVersion, expectedLibrarySize);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

	if (0 != portLibraryInitStatus) {
		J9PortLibraryVersion actualVersion;
		/* port lib init failure */
		switch (portLibraryInitStatus) {
		case J9PORT_ERROR_INIT_WRONG_MAJOR_VERSION: {
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
			j9port_getVersion(&j9portLibrary, &actualVersion);
#else
			portGetVersionFn(&j9portLibrary, &actualVersion);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

			fprintf(stderr,"Error: Port Library failed to initialize: expected major version %u, actual version is %u\n",
					portLibraryVersion.majorVersionNumber, actualVersion.majorVersionNumber);
			break;
		}
		case J9PORT_ERROR_INIT_WRONG_SIZE: {
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
			UDATA actualSize = j9port_getSize(&portLibraryVersion);
#else
			UDATA actualSize = portGetSizeFn(&portLibraryVersion);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
			fprintf(stderr,"Error: Port Library failed to initialize: expected library size %" J9PRIz "u, actual size is %" J9PRIz "u\n",
					expectedLibrarySize, actualSize);
			break;
		}
		case J9PORT_ERROR_INIT_WRONG_CAPABILITIES: {
			fprintf(stderr,"Error: Port Library failed to initialize: capabilities do not match\n");
			break;
		}
		default: fprintf(stderr,"Error: Port Library failed to initialize: %i\n", portLibraryInitStatus); break;
		/* need this to handle legacy port libraries */
		}

#if defined(AIXPPC)
		/* Release memory if allocated by strdup() in backupLibpath() previously */
		freeBackupLibpath(&libpathBackup);

		/* restore LIBPATH to avoid polluting child processes */
		setLibpath(origLibpath);
#endif /* AIXPPC */
		result = JNI_ERR;
		goto exit;
	}

	/* Get the thread library memory categories */
	{
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
		IDATA threadCategoryResult = omrthread_lib_control(J9THREAD_LIB_CONTROL_GET_MEM_CATEGORIES, (UDATA)&j9MasterMemCategorySet);
#else
		IDATA threadCategoryResult = f_threadLibControl(J9THREAD_LIB_CONTROL_GET_MEM_CATEGORIES, (UDATA)&j9MasterMemCategorySet);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

		if (threadCategoryResult) {
			fprintf(stderr,"Error: Couldn't get memory categories from thread library.\n");
#if defined(AIXPPC)
			/* Release memory if allocated by strdup() in backupLibpath() previously */
			freeBackupLibpath(&libpathBackup);

			/* restore LIBPATH to avoid polluting child processes */
			setLibpath(origLibpath);
#endif /* AIXPPC */
			result = JNI_ERR;
			goto exit;
		}
	}
	/* Register the J9 memory categories with the port library */
	j9portLibrary.omrPortLibrary.port_control(&j9portLibrary.omrPortLibrary, J9PORT_CTLDATA_MEM_CATEGORIES_SET, (UDATA)&j9MasterMemCategorySet);

	j2seVersion = getVersionFromPropertiesFile();
	if (J2SE_18 > j2seVersion) {
		fprintf(stderr, "Invalid version 0x%" J9PRIz "x detected in classlib.properties!\n", j2seVersion);
		result = JNI_ERR;
		goto exit;
	}
	setNLSCatalog(&j9portLibrary, j2seVersion);

#ifdef WIN32
	if (GetEnvironmentVariableW(IBM_MALLOCTRACE_STR, NULL, 0) > 0)
		ibmMallocTraceSet = TRUE;
	altJavaHomeSpecified = (GetEnvironmentVariableW(ALT_JAVA_HOME_DIR_STR, NULL, 0) > 0);
#endif
#if defined(J9UNIX) || defined(J9ZOS390)
	if (getenv(IBM_MALLOCTRACE_STR)) {
		ibmMallocTraceSet = TRUE;
	}
#endif /* defined(J9UNIX) || defined(J9ZOS390) */

	args = (JavaVMInitArgs *)vm_args;
	launcherArgumentsSize = initialArgumentScan(args, &specialArgs);
	localVerboseLevel = specialArgs.localVerboseLevel;

	if (VERBOSE_INIT == localVerboseLevel) {
		createParams.flags |= J9_CREATEJAVAVM_VERBOSE_INIT;
	}

	if (ibmMallocTraceSet) {
		/* We have no access to the original command line, so cannot
		 * pass in a valid argv to this function.
		 * Currently this function only used argv to help set the NLS
		 * catalog.
		 * The catalog has already been set above. */
		memoryCheck_initialize(&j9portLibrary, "all", NULL);
	}

	{
		char *optionsDefaultFileLocation = NULL;
		BOOLEAN doAddExtDir = FALSE;
		J9JavaVMArgInfoList vmArgumentsList;
		J9ZipFunctionTable *zipFuncs = NULL;
		vmArgumentsList.pool = pool_new(sizeof(J9JavaVMArgInfo),
				32, /* expect at least ~16 arguments, overallocate to accommodate user arguments */
				0, 0,
				J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(&j9portLibrary));
		if (NULL == vmArgumentsList.pool) {
			result = JNI_ERR;
			goto exit;
		}
		vmArgumentsList.head = NULL;
		vmArgumentsList.tail = NULL;
		if (NULL != specialArgs.executableJarPath) {
#if !CALL_BUNDLED_FUNCTIONS_DIRECTLY
			if (NULL == f_j9_GetInterface) {
#ifdef WIN32
				f_j9_GetInterface = (J9GetInterface) GetProcAddress (j9vm_dllHandle, (LPCSTR) "J9_GetInterface");
#else
				f_j9_GetInterface = (J9GetInterface) dlsym (j9vm_dllHandle, "J9_GetInterface");
#endif /* WIN32 */
			}
			/* j9binBuffer->data is null terminated */
			zipFuncs = (J9ZipFunctionTable*) f_j9_GetInterface(IF_ZIPSUP, &j9portLibrary, j9binBuffer->data);
#else /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
			zipFuncs = (J9ZipFunctionTable*) J9_GetInterface(IF_ZIPSUP, &j9portLibrary, j9binBuffer);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
		}
		if ((j2seVersion & J2SE_SERVICE_RELEASE_MASK) >= J2SE_19) {
			optionsDefaultFileLocation = jvmBufferData(j9libBuffer);
		} else {
			optionsDefaultFileLocation = jvmBufferData(j9binBuffer);
			doAddExtDir = TRUE;
		}
		/* now add implicit VM arguments */
		if (
				/* Add the default options file */
				(0 != addOptionsDefaultFile(&j9portLibrary, &vmArgumentsList, optionsDefaultFileLocation, localVerboseLevel))
				|| (0 != addXjcl(&j9portLibrary, &vmArgumentsList, j2seVersion))
				|| (0 != addBootLibraryPath(&j9portLibrary, &vmArgumentsList, "-Dcom.ibm.oti.vm.bootstrap.library.path=",
						jvmBufferData(j9binBuffer), jvmBufferData(jrebinBuffer)))
				|| (0 != addBootLibraryPath(&j9portLibrary, &vmArgumentsList, "-Dsun.boot.library.path=",
						jvmBufferData(j9binBuffer), jvmBufferData(jrebinBuffer)))
				|| (0 != addJavaLibraryPath(&j9portLibrary, &vmArgumentsList, argEncoding, jvmInSubdir,
						jvmBufferData(j9binBuffer), jvmBufferData(jrebinBuffer),
						libpathValue, ldLibraryPathValue))
				|| (0 != addJavaHome(&j9portLibrary, &vmArgumentsList, altJavaHomeSpecified, jvmBufferData(j9libBuffer)))
				|| (doAddExtDir && (0 != addExtDir(&j9portLibrary, &vmArgumentsList, jvmBufferData(j9libBuffer), args, j2seVersion)))
				|| (0 != addUserDir(&j9portLibrary, &vmArgumentsList, cwd))
				|| (0 != addJavaPropertiesOptions(&j9portLibrary, &vmArgumentsList, localVerboseLevel))
				|| (0 != addJarArguments(&j9portLibrary, &vmArgumentsList, specialArgs.executableJarPath, zipFuncs, localVerboseLevel))
				|| (0 != addEnvironmentVariables(&j9portLibrary, args, &vmArgumentsList, localVerboseLevel))
				|| (0 != addLauncherArgs(&j9portLibrary, args, launcherArgumentsSize, &vmArgumentsList,
						&xServiceBuffer, argEncoding, localVerboseLevel))
#ifdef J9VM_OPT_HARMONY
				/* pass in the Harmony library */
				|| (0 != addHarmonyPortLibrary(&j9portLibrary, &vmArgumentsList, localVerboseLevel))
#endif /* J9VM_OPT_HARMONY */
				|| (0 != addXserviceArgs(&j9portLibrary, &vmArgumentsList, xServiceBuffer, localVerboseLevel))
		) {
			result = JNI_ERR;
			goto exit;
		}

		if (NULL != libpathValue) {
			free((void *)libpathValue);
		}
		if (NULL != ldLibraryPathValue) {
			free((void *)ldLibraryPathValue);
		}
		j9ArgList = createJvmInitArgs(&j9portLibrary, args, &vmArgumentsList, &argEncoding);
		if (ARG_ENCODING_LATIN == argEncoding) {
			createParams.flags |= J9_CREATEJAVAVM_ARGENCODING_LATIN;
		} else if (ARG_ENCODING_UTF == argEncoding) {
			createParams.flags |= J9_CREATEJAVAVM_ARGENCODING_UTF8;
		} else if (ARG_ENCODING_PLATFORM == argEncoding) {
			createParams.flags |= J9_CREATEJAVAVM_ARGENCODING_PLATFORM;
		}

		pool_kill(vmArgumentsList.pool);
		if (NULL == j9ArgList) {
			result = JNI_ERR;
			goto exit;
		}
	}

	if(jvmInSubdir) {
		j2seVersion |= J2SE_LAYOUT_VM_IN_SUBDIR;
	}

	createParams.j2seVersion = j2seVersion;
	createParams.j2seRootDirectory = jvmBufferData(j9binBuffer);
	createParams.j9libvmDirectory = jvmBufferData(j9libvmBuffer);

	createParams.portLibrary = &j9portLibrary;
	createParams.globalJavaVM = &BFUjavaVM;

	if (VERBOSE_INIT == localVerboseLevel) {
		fprintf(stderr, "VM known paths\t- j9libvm directory: %s\n\t\t- j2seRoot directory: %s\n",
			createParams.j9libvmDirectory,
			createParams.j2seRootDirectory);

		printVmArgumentsList(j9ArgList);
	}
	createParams.vm_args = j9ArgList;

#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
	result = J9_CreateJavaVM((JavaVM**)&BFUjavaVM, penv, &createParams);
#else
	result = globalCreateVM((JavaVM**)&BFUjavaVM, penv, &createParams);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY  */

#ifdef DEBUG
	fprintf(stdout,"Finished, result %d, env %llx\n", result, (long long)*penv);
	fflush(stdout);
#endif
	if (result == JNI_OK) {
		BOOLEAN initializeReflectAccessors = TRUE;
		JavaVM * vm = (JavaVM*)BFUjavaVM;
		*pvm = vm;

#if !defined(HARMONY_VM)
		/* Initialize the Sun VMI */
		ENSURE_VMI();
#endif

		memcpy(&globalInvokeInterface, *vm, sizeof(J9InternalVMFunctions));
		globalDestroyVM = globalInvokeInterface.DestroyJavaVM;
		globalInvokeInterface.DestroyJavaVM = DestroyJavaVM;
		issueWriteBarrier();
		*vm = (struct JNIInvokeInterface_ *) &globalInvokeInterface;

#if !defined(HARMONY_VM)
		/* Harmony Select does not want any of the Win32 threading or reflection globals init. */

#ifdef WIN32
		result = initializeWin32ThreadEvents(BFUjavaVM);
		if (result != JNI_OK) {
			(**pvm)->DestroyJavaVM(*pvm);
			goto exit;
		}
#endif

		/* Initialize the VM interface */
		result = initializeReflectionGlobals(*penv, initializeReflectAccessors);
		if (result != JNI_OK) {
			(**pvm)->DestroyJavaVM(*pvm);
			goto exit;
		}
#endif /* !defined(HARMONY_VM) */

	} else {
		freeGlobals();
	}

	if ((result == JNI_OK) && (BFUjavaVM->runtimeFlags & J9_RUNTIME_SHOW_VERSION)) {
		JNIEnv * env = *penv;
		jclass clazz = (*env)->FindClass(env, "sun/misc/Version");

		if (clazz == NULL) {
			(*env)->ExceptionClear(env);
		} else {
			jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "print", "()V");

			if (mid != NULL) {
				(*env)->CallStaticVoidMethod(env, clazz, mid);
				if (!(*env)->ExceptionCheck(env)) {
					j9portLibrary.omrPortLibrary.tty_printf(&j9portLibrary.omrPortLibrary, "\n");
				}
			}
			(*env)->ExceptionClear(env);
			(*env)->DeleteLocalRef(env, clazz);
		}
	}

#if defined(AIXPPC)
	/* restore LIBPATH to avoid polluting child processes */
	restoreLibpath(&libpathBackup);
#ifdef DEBUG_TEST
	testBackupAndRestoreLibpath();
#endif /* DEBUG_TEST */
#endif /* AIXPPC */

	if (JNI_OK == result) {
		J9JavaVM *env = (J9JavaVM *) BFUjavaVM;
		J9VMThread *currentThread = env->mainThread;
		omrthread_t thread = currentThread->osThread;
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
		omrthread_set_category(thread, J9THREAD_CATEGORY_APPLICATION_THREAD, J9THREAD_TYPE_SET_MODIFY);
#else
		f_setCategory(thread, J9THREAD_CATEGORY_APPLICATION_THREAD, J9THREAD_TYPE_SET_MODIFY);
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	}

exit:
#if CALL_BUNDLED_FUNCTIONS_DIRECTLY
	if (NULL != attachedThread) {
		omrthread_detach(attachedThread);
	}
#else /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */
	if (NULL != attachedThread) {
		f_threadDetach(attachedThread);
	}
#endif /* CALL_BUNDLED_FUNCTIONS_DIRECTLY */

	return result;
}


JVM_GetClassConstantPool(JNIEnv *env, jclass target)
{
	Trc_SC_GetClassConstantPool(env);
	exit(205);
}


int findDirContainingFile(J9StringBuffer **result, char *paths, char pathSeparator, char *fileToFind, int elementsToSkip) {
	char *startOfDir, *endOfDir, *pathsCopy;
	int   isEndOfPaths, foundIt, count=elementsToSkip;

	/* Copy input as it is modified */
	paths = strdup(paths);
	if (!paths) {
		return FALSE;
	}

	pathsCopy = paths;
	while(elementsToSkip--) {
		pathsCopy = strchr(pathsCopy, pathSeparator);
		if(pathsCopy) {
			pathsCopy++; /* advance past separator */
		} else {
			free(paths);
			return 0;
		}
	}

	/* Search each dir in the list for fileToFind */
	startOfDir = endOfDir = pathsCopy;
	for (isEndOfPaths=FALSE, foundIt=FALSE; !foundIt && !isEndOfPaths; endOfDir++) {

		isEndOfPaths = endOfDir[0] == '\0';
		if (isEndOfPaths || (endOfDir[0] == pathSeparator))  {
			endOfDir[0] = '\0';
			if (strlen(startOfDir) && isFileInDir(startOfDir, fileToFind)) {
				foundIt = TRUE;
				if (NULL != *result) {
					free(*result);
					*result = NULL;
				}
				*result = jvmBufferCat(NULL, startOfDir);
			}
			startOfDir = endOfDir+1;
			count+=1;
		}
	}

	free(paths); /* from strdup() */
	if(foundIt) {
		return count;
	} else {
		return 0;
	}
}


JVM_Open(const char* filename, jint flags, jint mode)
{
	int errorVal = 0;
	jint returnVal = 0;

	/* On OSX, stat64 and fstat64 are deprecated.
	 * Thus, stat and fstat are used on OSX.
	 */
#if defined(J9UNIX) && !defined(J9ZTPF) && !defined(OSX)
	struct stat64 tempStat;
	int doUnlink = 0;
#endif /* defined(J9UNIX) && !defined(J9ZTPF) && !defined(OSX) */
#if defined(J9ZOS390) || defined(J9ZTPF) || defined(OSX)
	struct stat tempStat;
	int doUnlink = 0;
#endif /* defined(J9ZOS390) || defined(J9ZTPF) || defined(OSX) */

	Trc_SC_Open_Entry(filename, flags, mode);

#define JVM_EEXIST -100

#ifdef WIN32
#ifdef __IBMC__
#define EXTRA_OPEN_FLAGS O_NOINHERIT | O_BINARY
#else
#define EXTRA_OPEN_FLAGS _O_NOINHERIT | _O_BINARY
#endif
#endif

#if defined(J9UNIX) || defined(J9ZOS390)
#if defined(OSX)
#define EXTRA_OPEN_FLAGS 0
#else
#define EXTRA_OPEN_FLAGS O_LARGEFILE
#endif /* defined(OSX) */

#ifndef O_DSYNC
#define O_DSYNC O_SYNC
#endif

	doUnlink = (flags & O_TEMPORARY);
#if !defined(J9ZTPF)
    flags &= (O_CREAT | O_APPEND | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY | O_EXCL | O_NOCTTY | O_NONBLOCK | O_NDELAY | O_SYNC | O_DSYNC);
#else /* !defined(J9ZTPF) */
    flags &= (O_CREAT | O_APPEND | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY | O_EXCL | O_NOCTTY | O_NONBLOCK | O_SYNC | O_DSYNC);
#endif /* !defined(J9ZTPF) */
#endif /* defined(J9UNIX) || defined(J9ZOS390) */

	/* For some reason, although JVM_NativePath is called on the filenames, some of them seem to
		get mangled between JVM_NativePath being called and JVM_open being called */
	filename = JVM_NativePath((char *)filename);

#if defined(J9UNIX) || defined(J9ZOS390)
	do {
		errorVal = 0;
#endif /* defined(J9UNIX) || defined(J9ZOS390) */

#ifdef J9OS_I5
	returnVal = Xj9Open_JDK6((char *)filename, (flags | EXTRA_OPEN_FLAGS), mode);
#else
	returnVal = open(filename, (flags | EXTRA_OPEN_FLAGS), mode);
#endif
	if (-1 == returnVal) {
		errorVal = errno;
	}

#if defined(J9UNIX) || defined(J9ZOS390)
	/* Unix open() call does not reject directories, so extra checks required */
	if ((returnVal>=0) && (J9FSTAT(returnVal, &tempStat)==-1)) {
		Trc_SC_Open_fstat64(filename);
		close(returnVal);
		return -1;
	}
	if ((returnVal>=0) && S_ISDIR(tempStat.st_mode)) {
		char buf[1];

		Trc_SC_Open_isDirectory(filename);

		/* force errno to be EISDIR in case JVM_GetLastErrorString is called */
		errno = EISDIR;

		close(returnVal);
		return -1;
	}

	/* On unices, open() may return EAGAIN or EINTR, and should then be re-invoked */
	}
	while ((-1 == returnVal) && ((EAGAIN == errorVal) || (EINTR == errorVal)));

	/* Unix does not have an O_TEMPORARY flag. Unlink if Sovereign O_TEMPORARY flag passed in. */
	if ((returnVal>=0) && doUnlink)
		unlink(filename);
#endif /* defined(J9UNIX) || defined(J9ZOS390) */

	if (returnVal<0) {
		Trc_SC_Open_error(filename, errorVal);
	} else {
		Trc_SC_Open_Exit(filename, returnVal);
	}

	if (returnVal>=0)
		return returnVal;
	else if (EEXIST == errorVal)
		return JVM_EEXIST;
	else
		return -1;
}


int jio_fprintf(FILE * stream, const char * format, ...) {
	va_list args;

	Trc_SC_fprintf_Entry();

	va_start( args, format );
	vfprintf(stream, format, args);
	va_end( args );

	Trc_SC_fprintf_Exit(0);

	return 0;
}


new_device (u2fh_devs * devs)
{
  struct u2fdevice *new = malloc (sizeof (struct u2fdevice));
  if (new == NULL)
    {
      return NULL;
    }
  memset (new, 0, sizeof (struct u2fdevice));
  new->id = devs->max_id++;
  if (devs->first == NULL)
    {
      devs->first = new;
    }
  else
    {
      struct u2fdevice *dev;
      for (dev = devs->first; dev != NULL; dev = dev->next)
	{
	  if (dev->next == NULL)
	    {
	      break;
	    }
	}
      dev->next = new;
    }
  return new;
}


u2fh_get_device_description (u2fh_devs * devs, unsigned index, char *out,
			     size_t * len)
{
  size_t i;
  struct u2fdevice *dev = get_device (devs, index);

  if (!dev)
    {
      return U2FH_NO_U2F_DEVICE;
    }
  i = strlen (dev->device_string);
  if (i < *len)
    {
      *len = i;
    }
  else
    {
      return U2FH_MEMORY_ERROR;
    }
  strcpy (out, dev->device_string);
  return U2FH_OK;
}


int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
		struct list_head *uf, bool downgrade)
{
	unsigned long end;
	struct vm_area_struct *vma, *prev, *last;

	if ((offset_in_page(start)) || start > TASK_SIZE || len > TASK_SIZE-start)
		return -EINVAL;

	len = PAGE_ALIGN(len);
	if (len == 0)
		return -EINVAL;

	/* Find the first overlapping VMA */
	vma = find_vma(mm, start);
	if (!vma)
		return 0;
	prev = vma->vm_prev;
	/* we have  start < vma->vm_end  */

	/* if it doesn't overlap, we have nothing.. */
	end = start + len;
	if (vma->vm_start >= end)
		return 0;

	/*
	 * If we need to split any vma, do it now to save pain later.
	 *
	 * Note: mremap's move_vma VM_ACCOUNT handling assumes a partially
	 * unmapped vm_area_struct will remain in use: so lower split_vma
	 * places tmp vma above, and higher split_vma places tmp vma below.
	 */
	if (start > vma->vm_start) {
		int error;

		/*
		 * Make sure that map_count on return from munmap() will
		 * not exceed its limit; but let map_count go just above
		 * its limit temporarily, to help free resources as expected.
		 */
		if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count)
			return -ENOMEM;

		error = __split_vma(mm, vma, start, 0);
		if (error)
			return error;
		prev = vma;
	}

	/* Does it split the last one? */
	last = find_vma(mm, end);
	if (last && end > last->vm_start) {
		int error = __split_vma(mm, last, end, 1);
		if (error)
			return error;
	}
	vma = prev ? prev->vm_next : mm->mmap;

	if (unlikely(uf)) {
		/*
		 * If userfaultfd_unmap_prep returns an error the vmas
		 * will remain splitted, but userland will get a
		 * highly unexpected error anyway. This is no
		 * different than the case where the first of the two
		 * __split_vma fails, but we don't undo the first
		 * split, despite we could. This is unlikely enough
		 * failure that it's not worth optimizing it for.
		 */
		int error = userfaultfd_unmap_prep(vma, start, end, uf);
		if (error)
			return error;
	}

	/*
	 * unlock any mlock()ed ranges before detaching vmas
	 */
	if (mm->locked_vm) {
		struct vm_area_struct *tmp = vma;
		while (tmp && tmp->vm_start < end) {
			if (tmp->vm_flags & VM_LOCKED) {
				mm->locked_vm -= vma_pages(tmp);
				munlock_vma_pages_all(tmp);
			}

			tmp = tmp->vm_next;
		}
	}

	/* Detach vmas from rbtree */
	detach_vmas_to_be_unmapped(mm, vma, prev, end);

	/*
	 * mpx unmap needs to be called with mmap_sem held for write.
	 * It is safe to call it before unmap_region().
	 */
	arch_unmap(mm, vma, start, end);

	if (downgrade)
		downgrade_write(&mm->mmap_sem);

	unmap_region(mm, vma, prev, start, end);

	/* Fix up all other VM information */
	remove_vma_list(mm, vma);

	return downgrade ? 1 : 0;
}


LocatePackageList (
  IN  LIST_ENTRY                     *Database,
  IN  EFI_HII_HANDLE                 PackageList
  )
{
  LIST_ENTRY                         *Link;
  HII_DATABASE_RECORD                *Record;

  //
  // Get the specified package list and image package.
  //
  for (Link = GetFirstNode (Database);
       !IsNull (Database, Link);
       Link = GetNextNode (Database, Link)
      ) {
    Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
    if (Record->Handle == PackageList) {
      return Record->PackageList;
    }
  }
  return NULL;
}


Output1bitPixel (
  IN OUT EFI_IMAGE_INPUT             *Image,
  IN UINT8                           *Data,
  IN EFI_HII_IMAGE_PALETTE_INFO      *PaletteInfo
  )
{
  UINT16                             Xpos;
  UINT16                             Ypos;
  UINTN                              OffsetY;
  UINT8                              Index;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BitMapPtr;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      PaletteValue[2];
  EFI_HII_IMAGE_PALETTE_INFO         *Palette;
  UINTN                              PaletteSize;
  UINT8                              Byte;

  ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);

  BitMapPtr = Image->Bitmap;

  //
  // First entry corresponds to color 0 and second entry corresponds to color 1.
  //
  PaletteSize = 0;
  CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
  PaletteSize += sizeof (UINT16);
  Palette = AllocateZeroPool (PaletteSize);
  ASSERT (Palette != NULL);
  if (Palette == NULL) {
    return;
  }
  CopyMem (Palette, PaletteInfo, PaletteSize);

  ZeroMem (PaletteValue, sizeof (PaletteValue));
  CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
  CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
  FreePool (Palette);

  //
  // Convert the pixel from one bit to corresponding color.
  //
  for (Ypos = 0; Ypos < Image->Height; Ypos++) {
    OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos);
    //
    // All bits in these bytes are meaningful
    //
    for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) {
      Byte = *(Data + OffsetY + Xpos);
      for (Index = 0; Index < 8; Index++) {
        if ((Byte & (1 << Index)) != 0) {
          BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1];
        } else {
          BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0];
        }
      }
    }

    if (Image->Width % 8 != 0) {
      //
      // Padding bits in this byte should be ignored.
      //
      Byte = *(Data + OffsetY + Xpos);
      for (Index = 0; Index < Image->Width % 8; Index++) {
        if ((Byte & (1 << (8 - Index - 1))) != 0) {
          BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1];
        } else {
          BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0];
        }
      }
    }
  }
}


Output4bitPixel (
  IN OUT EFI_IMAGE_INPUT             *Image,
  IN UINT8                           *Data,
  IN EFI_HII_IMAGE_PALETTE_INFO      *PaletteInfo
  )
{
  UINT16                             Xpos;
  UINT16                             Ypos;
  UINTN                              OffsetY;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BitMapPtr;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      PaletteValue[16];
  EFI_HII_IMAGE_PALETTE_INFO         *Palette;
  UINTN                              PaletteSize;
  UINT16                             PaletteNum;
  UINT8                              Byte;

  ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);

  BitMapPtr = Image->Bitmap;

  //
  // The bitmap should allocate each color index starting from 0.
  //
  PaletteSize = 0;
  CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
  PaletteSize += sizeof (UINT16);
  Palette = AllocateZeroPool (PaletteSize);
  ASSERT (Palette != NULL);
  if (Palette == NULL) {
    return;
  }
  CopyMem (Palette, PaletteInfo, PaletteSize);
  PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));

  ZeroMem (PaletteValue, sizeof (PaletteValue));
  CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
  FreePool (Palette);

  //
  // Convert the pixel from 4 bit to corresponding color.
  //
  for (Ypos = 0; Ypos < Image->Height; Ypos++) {
    OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos);
    //
    // All bits in these bytes are meaningful
    //
    for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) {
      Byte = *(Data + OffsetY + Xpos);
      BitMapPtr[Ypos * Image->Width + Xpos * 2]     = PaletteValue[Byte >> 4];
      BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F];
    }

    if (Image->Width % 2 != 0) {
      //
      // Padding bits in this byte should be ignored.
      //
      Byte = *(Data + OffsetY + Xpos);
      BitMapPtr[Ypos * Image->Width + Xpos * 2]     = PaletteValue[Byte >> 4];
    }
  }
}


/* kex_agree_kex_hostkey
 * Agree on a Key Exchange method and a hostkey encoding type
 */
static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
                                 unsigned long kex_len, unsigned char *hostkey,
                                 unsigned long hostkey_len)
{
    const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
    unsigned char *s;

    if(session->kex_prefs) {
        s = (unsigned char *) session->kex_prefs;

        while(s && *s) {
            unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
            size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
            q = kex_agree_instr(kex, kex_len, s, method_len);
            if(q) {
                const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
                    kex_get_method_by_name((char *) s, method_len,
                                           (const LIBSSH2_COMMON_METHOD **)
                                           kexp);

                if(!method) {
                    /* Invalid method -- Should never be reached */
                    return -1;
                }

                /* We've agreed on a key exchange method,
                 * Can we agree on a hostkey that works with this kex?
                 */
                if(kex_agree_hostkey(session, method->flags, hostkey,
                                      hostkey_len) == 0) {
                    session->kex = method;
                    if(session->burn_optimistic_kexinit && (kex == q)) {
                        /* Server sent an optimistic packet,
                         * and client agrees with preference
                         * cancel burning the first KEX_INIT packet that comes in */
                        session->burn_optimistic_kexinit = 0;
                    }
                    return 0;
                }
            }

            s = p ? p + 1 : NULL;
        }
        return -1;
    }

    while(*kexp && (*kexp)->name) {
        s = kex_agree_instr(kex, kex_len,
                            (unsigned char *) (*kexp)->name,
                            strlen((*kexp)->name));
        if(s) {
            /* We've agreed on a key exchange method,
             * Can we agree on a hostkey that works with this kex?
             */
            if(kex_agree_hostkey(session, (*kexp)->flags, hostkey,
                                  hostkey_len) == 0) {
                session->kex = *kexp;
                if(session->burn_optimistic_kexinit && (kex == s)) {
                    /* Server sent an optimistic packet,
                     * and client agrees with preference
                     * cancel burning the first KEX_INIT packet that comes in */
                    session->burn_optimistic_kexinit = 0;
                }
                return 0;
            }
        }
        kexp++;


 */

static int
kex_method_ecdh_key_exchange
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
{
    int ret = 0;
    int rc = 0;
    unsigned char *s;
    libssh2_curve_type type;

    if(key_state->state == libssh2_NB_state_idle) {

        key_state->public_key_oct = NULL;
        key_state->state = libssh2_NB_state_created;
    }

    if(key_state->state == libssh2_NB_state_created) {
        rc = kex_session_ecdh_curve_type(session->kex->name, &type);

        if(rc != 0) {
            ret = _libssh2_error(session, -1,
                                 "Unknown KEX nistp curve type");
            goto ecdh_clean_exit;
        }

        rc = _libssh2_ecdsa_create_key(session, &key_state->private_key,
                                       &key_state->public_key_oct, &key_state->public_key_oct_len, type);

        if(rc != 0) {
            ret = _libssh2_error(session, rc,
                                 "Unable to create private key");
            goto ecdh_clean_exit;
        }

        key_state->request[0] = SSH2_MSG_KEX_ECDH_INIT;
        s = key_state->request + 1;
        _libssh2_store_str(&s, (const char *)key_state->public_key_oct, key_state->public_key_oct_len);
        key_state->request_len = key_state->public_key_oct_len + 5;

        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                       "Initiating ECDH SHA2 NISTP256");

        key_state->state = libssh2_NB_state_sent;
    }

    if(key_state->state == libssh2_NB_state_sent) {
        rc = _libssh2_transport_send(session, key_state->request,
                                     key_state->request_len, NULL, 0);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        else if(rc) {
            ret = _libssh2_error(session, rc,
                                 "Unable to send ECDH_INIT");
            goto ecdh_clean_exit;
        }

        key_state->state = libssh2_NB_state_sent1;
    }

    if(key_state->state == libssh2_NB_state_sent1) {
        rc = _libssh2_packet_require(session, SSH2_MSG_KEX_ECDH_REPLY,
                                     &key_state->data, &key_state->data_len,
                                     0, NULL, 0, &key_state->req_state);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        }
        else if(rc) {
            ret = _libssh2_error(session, rc,
                                 "Timeout waiting for ECDH_REPLY reply");
            goto ecdh_clean_exit;
        }

        key_state->state = libssh2_NB_state_sent2;
    }

    if(key_state->state == libssh2_NB_state_sent2) {

        (void)kex_session_ecdh_curve_type(session->kex->name, &type);

        ret = ecdh_sha2_nistp(session, type, key_state->data, key_state->data_len, (unsigned char *)key_state->public_key_oct,
                             key_state->public_key_oct_len, key_state->private_key, &key_state->exchange_state);

        if(ret == LIBSSH2_ERROR_EAGAIN) {
            return ret;
        }

        LIBSSH2_FREE(session, key_state->data);
    }

ecdh_clean_exit:

    if(key_state->public_key_oct) {
        LIBSSH2_FREE(session, key_state->public_key_oct);
        key_state->public_key_oct = NULL;
    }

    if(key_state->private_key) {
        _libssh2_ecdsa_free(key_state->private_key);
        key_state->private_key = NULL;
    }

    key_state->state = libssh2_NB_state_idle;


hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract)
{
    libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract);
    (void) session;

    if(keyctx != NULL)
        _libssh2_ecdsa_free(keyctx);

    *abstract = NULL;

    return 0;
}