jdk/src/solaris/native/java/lang/UNIXProcess_md.c
author duke
Sat, 01 Dec 2007 00:00:00 +0000
changeset 2 90ce3da70b43
child 48 dc5744ca15ea
permissions -rw-r--r--
Initial load
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
#undef  _LARGEFILE64_SOURCE
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
#define _LARGEFILE64_SOURCE 1
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
#include "jni.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
#include "jvm.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
#include "jvm_md.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
#include "jni_util.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
#include "io_util.h"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
 * Platform-specific support for java.lang.Process
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
#include <assert.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
#include <stddef.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
#include <stdlib.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
#include <sys/types.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
#include <ctype.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
#include <wait.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
#include <signal.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
#include <string.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
#include <errno.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
#include <dirent.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
#include <unistd.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
#include <fcntl.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
#include <limits.h>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
#ifndef STDIN_FILENO
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
#define STDIN_FILENO 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
#ifndef STDOUT_FILENO
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
#define STDOUT_FILENO 1
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
#ifndef STDERR_FILENO
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
#define STDERR_FILENO 2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
#ifndef SA_NOCLDSTOP
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
#define SA_NOCLDSTOP 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
#ifndef SA_RESTART
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
#define SA_RESTART 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
#define FAIL_FILENO (STDERR_FILENO + 1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
setSIGCHLDHandler(JNIEnv *env)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
    /* There is a subtle difference between having the signal handler
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
     * for SIGCHLD be SIG_DFL and SIG_IGN.  We cannot obtain process
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
     * termination information for child processes if the signal
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
     * handler is SIG_IGN.  It must be SIG_DFL.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
     * We used to set the SIGCHLD handler only on Linux, but it's
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
     * safest to set it unconditionally.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
     * Consider what happens if java's parent process sets the SIGCHLD
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
     * handler to SIG_IGN.  Normally signal handlers are inherited by
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
     * children, but SIGCHLD is a controversial case.  Solaris appears
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
     * to always reset it to SIG_DFL, but this behavior may be
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
     * non-standard-compliant, and we shouldn't rely on it.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
     * References:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
     * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
     * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    struct sigaction sa;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
    sa.sa_handler = SIG_DFL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
    sigemptyset(&sa.sa_mask);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
    sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
    if (sigaction(SIGCHLD, &sa, NULL) < 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
        JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
static void*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
xmalloc(JNIEnv *env, size_t size)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
    void *p = malloc(size);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
    if (p == NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
        JNU_ThrowOutOfMemoryError(env, NULL);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
    return p;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
 * If PATH is not defined, the OS provides some default value.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
 * Unfortunately, there's no portable way to get this value.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
 * Fortunately, it's only needed if the child has PATH while we do not.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
static const char*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
defaultPath(void)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
#ifdef __solaris__
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
    /* These really are the Solaris defaults! */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
    return (geteuid() == 0 || getuid() == 0) ?
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
        "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
        "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
#else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
    return ":/bin:/usr/bin";    /* glibc */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
static const char*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
effectivePath(void)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
    const char *s = getenv("PATH");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
    return (s != NULL) ? s : defaultPath();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
static int
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
countOccurrences(const char *s, char c)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
    int count;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
    for (count = 0; *s != '\0'; s++)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        count += (*s == c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
    return count;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
static const char * const *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
splitPath(JNIEnv *env, const char *path)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
    const char *p, *q;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
    char **pathv;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
    int i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
    int count = countOccurrences(path, ':') + 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
    pathv = NEW(char*, count+1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
    pathv[count] = NULL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
    for (p = path, i = 0; i < count; i++, p = q + 1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
        for (q = p; (*q != ':') && (*q != '\0'); q++)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
            ;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        if (q == p)             /* empty PATH component => "." */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
            pathv[i] = "./";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
        else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
            int addSlash = ((*(q - 1)) != '/');
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
            pathv[i] = NEW(char, q - p + addSlash + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
            memcpy(pathv[i], p, q - p);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
            if (addSlash)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
                pathv[i][q - p] = '/';
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
            pathv[i][q - p + addSlash] = '\0';
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
    return (const char * const *) pathv;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
 * Cached value of JVM's effective PATH.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
 * (We don't support putenv("PATH=...") in native code)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
static const char *parentPath;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
 * Split, canonicalized version of parentPath
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
static const char * const *parentPathv;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
static jfieldID field_exitcode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
Java_java_lang_UNIXProcess_initIDs(JNIEnv *env, jclass clazz)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
    field_exitcode = (*env)->GetFieldID(env, clazz, "exitcode", "I");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
    parentPath  = effectivePath();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
    parentPathv = splitPath(env, parentPath);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
    setSIGCHLDHandler(env);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
#ifndef WIFEXITED
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
#define WIFEXITED(status) (((status)&0xFF) == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
#ifndef WEXITSTATUS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
#ifndef WIFSIGNALED
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
#ifndef WTERMSIG
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
#define WTERMSIG(status) ((status)&0x7F)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
/* Block until a child process exits and return its exit code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
   Note, can only be called once for any given pid. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
JNIEXPORT jint JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
Java_java_lang_UNIXProcess_waitForProcessExit(JNIEnv* env,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
                                              jobject junk,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
                                              jint pid)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
    /* We used to use waitid() on Solaris, waitpid() on Linux, but
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
     * waitpid() is more standard, so use it on all POSIX platforms. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
    int status;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
    /* Wait for the child process to exit.  This returns immediately if
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
       the child has already exited. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
    while (waitpid(pid, &status, 0) < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
        switch (errno) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        case ECHILD: return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
        case EINTR: break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
        default: return -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
    if (WIFEXITED(status)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
         * The child exited normally; get its exit code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
        return WEXITSTATUS(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
    } else if (WIFSIGNALED(status)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
        /* The child exited because of a signal.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
         * The best value to return is 0x80 + signal number,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
         * because that is what all Unix shells do, and because
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
         * it allows callers to distinguish between process exit and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
         * process death by signal.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
         * Unfortunately, the historical behavior on Solaris is to return
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
         * the signal number, and we preserve this for compatibility. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
#ifdef __solaris__
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
        return WTERMSIG(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
#else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
        return 0x80 + WTERMSIG(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
    } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
         * Unknown exit code; pass it through.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
        return status;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
static int
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
closeDescriptors(void)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
    DIR *dp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
    struct dirent64 *dirp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
    int from_fd = FAIL_FILENO + 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
    /* We're trying to close all file descriptors, but opendir() might
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
     * itself be implemented using a file descriptor, and we certainly
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
     * don't want to close that while it's in use.  We assume that if
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
     * opendir() is implemented using a file descriptor, then it uses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
     * the lowest numbered file descriptor, just like open().  So we
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
     * close a couple explicitly.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
    close(from_fd);             /* for possible use by opendir() */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
    close(from_fd + 1);         /* another one for good luck */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
    if ((dp = opendir("/proc/self/fd")) == NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
        return 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
    /* We use readdir64 instead of readdir to work around Solaris bug
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
     * 6395699: /proc/self/fd fails to report file descriptors >= 1024 on Solaris 9
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
    while ((dirp = readdir64(dp)) != NULL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
        int fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
        if (isdigit(dirp->d_name[0]) &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
            (fd = strtol(dirp->d_name, NULL, 10)) >= from_fd + 2)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            close(fd);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
    closedir(dp);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
    return 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
moveDescriptor(int fd_from, int fd_to)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
    if (fd_from != fd_to) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
        dup2(fd_from, fd_to);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
        close(fd_from);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
static const char *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
getBytes(JNIEnv *env, jbyteArray arr)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
    return arr == NULL ? NULL :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
        (const char*) (*env)->GetByteArrayElements(env, arr, NULL);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
    if (parr != NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
        (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
initVectorFromBlock(const char**vector, const char* block, int count)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
    int i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
    const char *p;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
    for (i = 0, p = block; i < count; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
        /* Invariant: p always points to the start of a C string. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
        vector[i] = p;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
        while (*(p++));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
    vector[count] = NULL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
    static const char * const format = "error=%d, %s";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
    const char *detail = defaultDetail;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
    char *errmsg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
    jstring s;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
    if (errnum != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
        const char *s = strerror(errnum);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
        if (strcmp(s, "Unknown error") != 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
            detail = s;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
    /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
    errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
    sprintf(errmsg, format, errnum, detail);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
    s = JNU_NewStringPlatform(env, errmsg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
    if (s != NULL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
        jobject x = JNU_NewObjectByName(env, "java/io/IOException",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
                                        "(Ljava/lang/String;)V", s);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
        if (x != NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
            (*env)->Throw(env, x);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
    free(errmsg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
#ifdef DEBUG_PROCESS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
/* Debugging process code is difficult; where to write debug output? */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
debugPrint(char *format, ...)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
    FILE *tty = fopen("/dev/tty", "w");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
    va_list ap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
    va_start(ap, format);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
    vfprintf(tty, format, ap);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
    va_end(ap);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
    fclose(tty);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
#endif /* DEBUG_PROCESS */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
/* Version of execvpe when child's PATH differs from parent's */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
static int
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
execvp_usingParentPath(const char *file, const char *const argv[])
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
    char expanded_file[PATH_MAX];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
    int filelen = strlen(file);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
    int sticky_errno = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
    const char * const * dirs;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
    /* Search parent's PATH */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
    for (dirs = parentPathv; *dirs; dirs++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
        const char * dir = *dirs;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
        int dirlen = strlen(dir);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
        if (filelen + dirlen + 1 >= PATH_MAX) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
            /* Resist the urge to remove this limit;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
             * calling malloc after fork is unsafe. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
            errno = ENAMETOOLONG;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
            continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
        strcpy(expanded_file, dir);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
        strcpy(expanded_file + dirlen, file);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
        execvp(expanded_file, (char **) argv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
        /* There are 3 responses to various classes of errno:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
         * return immediately, continue (especially for ENOENT),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
         * or continue with "sticky" errno.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
         * From exec(3):
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
         * If permission is denied for a file (the attempted
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
         * execve returned EACCES), these functions will continue
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
         * searching the rest of the search path.  If no other
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
         * file is found, however, they will return with the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
         * global variable errno set to EACCES.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
        switch (errno) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
        case EACCES:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
            sticky_errno = errno;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
            /* FALLTHRU */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
        case ENOENT:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
        case ENOTDIR:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
#ifdef ELOOP
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
        case ELOOP:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
#ifdef ESTALE
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
        case ESTALE:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
#ifdef ENODEV
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
        case ENODEV:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
#ifdef ETIMEDOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
        case ETIMEDOUT:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
            break; /* Try other directories in PATH */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
        default:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
            return -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
    if (sticky_errno != 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
        errno = sticky_errno;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
    return -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
/* execvpe should have been included in the Unix standards. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
static int
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
execvpe(const char *file, const char *const argv[], const char *const envp[])
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
    /* This is one of the rare times it's more portable to declare an
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
     * external symbol explicitly, rather than via a system header.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
     * The declaration is standardized as part of UNIX98, but there is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
     * no standard (not even de-facto) header file where the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
     * declaration is to be found.  See:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
     * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
     * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
     * "All identifiers in this volume of IEEE Std 1003.1-2001, except
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
     * environ, are defined in at least one of the headers" (!)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
    extern char **environ;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
    if (envp != NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
        environ = (char **) envp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
    if (/* Parent and child environment the same?  Use child PATH. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
        (envp == NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
        /* http://www.opengroup.org/onlinepubs/009695399/functions/exec.html
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
         * "If the file argument contains a slash character, it is used as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
         * the pathname for this file.  Otherwise, the path prefix for this
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
         * file is obtained by a search of the directories passed in the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
         * PATH environment variable" */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
        || (strchr(file, '/') != NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
        /* Parent and child PATH the same?  Use child PATH. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
        || (strcmp(parentPath, effectivePath()) == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
        /* We want ENOENT, not EACCES, for zero-length program names. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
        || (*file == '\0'))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
        return execvp(file, (char **) argv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
    else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
        return execvp_usingParentPath(file, argv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
static void
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
closeSafely(int fd)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
    if (fd != -1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
        close(fd);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
#ifndef __solaris__
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
#undef fork1
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
#define fork1() fork()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
#endif
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
JNIEXPORT jint JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
                                       jobject process,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
                                       jbyteArray prog,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
                                       jbyteArray argBlock, jint argc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
                                       jbyteArray envBlock, jint envc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
                                       jbyteArray dir,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
                                       jboolean redirectErrorStream,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
                                       jobject stdin_fd,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
                                       jobject stdout_fd,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
                                       jobject stderr_fd)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
    int errnum;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
    int resultPid = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
    int in[2], out[2], err[2], fail[2];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
    const char **argv = NULL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
    const char **envv = NULL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
    const char *pprog     = getBytes(env, prog);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
    const char *pargBlock = getBytes(env, argBlock);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
    const char *penvBlock = getBytes(env, envBlock);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
    const char *pdir      = getBytes(env, dir);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
    in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
    assert(prog != NULL && argBlock != NULL);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
    if (pprog     == NULL) goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
    if (pargBlock == NULL) goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
    if (envBlock  != NULL && penvBlock == NULL) goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
    if (dir       != NULL && pdir      == NULL) goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
    /* Convert pprog + pargBlock into a char ** argv */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
    if ((argv = NEW(const char *, argc + 2)) == NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
        goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
    argv[0] = pprog;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
    initVectorFromBlock(argv+1, pargBlock, argc);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
    if (envBlock != NULL) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   524
        /* Convert penvBlock into a char ** envv */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
        if ((envv = NEW(const char *, envc + 1)) == NULL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
            goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
        initVectorFromBlock(envv, penvBlock, envc);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   528
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
    if ((pipe(in)   < 0) ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
        (pipe(out)  < 0) ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
        (pipe(err)  < 0) ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
        (pipe(fail) < 0)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
        throwIOException(env, errno, "Bad file descriptor");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   535
        goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   536
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   537
90ce3da70b43 Initial load
duke
parents:
diff changeset
   538
    resultPid = fork1();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   539
    if (resultPid < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
        throwIOException(env, errno, "Fork failed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
        goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
    if (resultPid == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   545
        /* Child process */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
        /* Close the parent sides of the pipe.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
           Give the child sides of the pipes the right fileno's.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
           Closing pipe fds here is redundant, since closeDescriptors()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
           would do it anyways, but a little paranoia is a good thing. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
        /* Note: it is possible for in[0] == 0 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
        close(in[1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
        moveDescriptor(in[0], STDIN_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
        close(out[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
        moveDescriptor(out[1], STDOUT_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
        close(err[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
        if (redirectErrorStream) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
            close(err[1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
            dup2(STDOUT_FILENO, STDERR_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
            moveDescriptor(err[1], STDERR_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
        close(fail[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
        moveDescriptor(fail[1], FAIL_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   565
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
        /* close everything */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
        if (closeDescriptors() == 0) { /* failed,  close the old way */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
            int max_fd = (int)sysconf(_SC_OPEN_MAX);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
            int i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
            for (i = FAIL_FILENO + 1; i < max_fd; i++)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
                close(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
        /* change to the new working directory */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
        if (pdir != NULL && chdir(pdir) < 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
            goto WhyCantJohnnyExec;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
        if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
            goto WhyCantJohnnyExec;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
        execvpe(argv[0], argv, envv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
    WhyCantJohnnyExec:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
        /* We used to go to an awful lot of trouble to predict whether the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
         * child would fail, but there is no reliable way to predict the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
         * success of an operation without *trying* it, and there's no way
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
         * to try a chdir or exec in the parent.  Instead, all we need is a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
         * way to communicate any failure back to the parent.  Easy; we just
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
         * send the errno back to the parent over a pipe in case of failure.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
         * The tricky thing is, how do we communicate the *success* of exec?
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
         * We use FD_CLOEXEC together with the fact that a read() on a pipe
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
         * yields EOF when the write ends (we have two of them!) are closed.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
        errnum = errno;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
        write(FAIL_FILENO, &errnum, sizeof(errnum));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   596
        close(FAIL_FILENO);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   597
        _exit(-1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   598
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   599
90ce3da70b43 Initial load
duke
parents:
diff changeset
   600
    /* parent process */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   601
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
    close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
    if (read(fail[0], &errnum, sizeof(errnum)) != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
        waitpid(resultPid, NULL, 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
        throwIOException(env, errnum, "Exec failed");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
        goto Catch;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
    (*env)->SetIntField(env, stdin_fd,  IO_fd_fdID, in [1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
    (*env)->SetIntField(env, stdout_fd, IO_fd_fdID, out[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
    (*env)->SetIntField(env, stderr_fd, IO_fd_fdID, err[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
 Finally:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
    /* Always clean up the child's side of the pipes */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
    closeSafely(in [0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
    closeSafely(out[1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
    closeSafely(err[1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
    /* Always clean up fail descriptors */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   620
    closeSafely(fail[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
    closeSafely(fail[1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
90ce3da70b43 Initial load
duke
parents:
diff changeset
   623
    free(argv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
    free(envv);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   625
90ce3da70b43 Initial load
duke
parents:
diff changeset
   626
    releaseBytes(env, prog,     pprog);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   627
    releaseBytes(env, argBlock, pargBlock);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   628
    releaseBytes(env, envBlock, penvBlock);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
    releaseBytes(env, dir,      pdir);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
90ce3da70b43 Initial load
duke
parents:
diff changeset
   631
    return resultPid;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
 Catch:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
    /* Clean up the parent's side of the pipes in case of failure only */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   635
    closeSafely(in [1]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   636
    closeSafely(out[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
    closeSafely(err[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
    goto Finally;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   639
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   640
90ce3da70b43 Initial load
duke
parents:
diff changeset
   641
JNIEXPORT void JNICALL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   642
Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   643
{
90ce3da70b43 Initial load
duke
parents:
diff changeset
   644
    kill(pid, SIGTERM);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   645
}