jdk/src/jdk.attach/aix/native/libattach/AixVirtualMachine.c
changeset 25859 3317bb8137f4
parent 23589 05e692d15fcd
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * Copyright 2014 SAP AG. All rights reserved.
       
     4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     5  *
       
     6  * This code is free software; you can redistribute it and/or modify it
       
     7  * under the terms of the GNU General Public License version 2 only, as
       
     8  * published by the Free Software Foundation.  Oracle designates this
       
     9  * particular file as subject to the "Classpath" exception as provided
       
    10  * by Oracle in the LICENSE file that accompanied this code.
       
    11  *
       
    12  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    15  * version 2 for more details (a copy is included in the LICENSE file that
       
    16  * accompanied this code).
       
    17  *
       
    18  * You should have received a copy of the GNU General Public License version
       
    19  * 2 along with this work; if not, write to the Free Software Foundation,
       
    20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    21  *
       
    22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    23  * or visit www.oracle.com if you need additional information or have any
       
    24  * questions.
       
    25  */
       
    26 
       
    27 #include "jni.h"
       
    28 #include "jni_util.h"
       
    29 
       
    30 #include <stdio.h>
       
    31 #include <stdlib.h>
       
    32 #include <string.h>
       
    33 #include <errno.h>
       
    34 #include <unistd.h>
       
    35 #include <signal.h>
       
    36 #include <dirent.h>
       
    37 #include <ctype.h>
       
    38 #include <sys/types.h>
       
    39 #include <sys/socket.h>
       
    40 #include <sys/stat.h>
       
    41 #include <sys/un.h>
       
    42 
       
    43 /*
       
    44  * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all
       
    45  * occurrences of the string "Linux" have been replaced by "Aix".
       
    46  */
       
    47 
       
    48 #include "sun_tools_attach_AixVirtualMachine.h"
       
    49 
       
    50 #define RESTARTABLE(_cmd, _result) do { \
       
    51   do { \
       
    52     _result = _cmd; \
       
    53   } while((_result == -1) && (errno == EINTR)); \
       
    54 } while(0)
       
    55 
       
    56 
       
    57 /*
       
    58  * Class:     sun_tools_attach_AixVirtualMachine
       
    59  * Method:    socket
       
    60  * Signature: ()I
       
    61  */
       
    62 JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_socket
       
    63   (JNIEnv *env, jclass cls)
       
    64 {
       
    65     int fd = socket(PF_UNIX, SOCK_STREAM, 0);
       
    66     if (fd == -1) {
       
    67         JNU_ThrowIOExceptionWithLastError(env, "socket");
       
    68     }
       
    69     /* added time out values */
       
    70     else {
       
    71         struct timeval tv;
       
    72         tv.tv_sec = 2 * 60;
       
    73         tv.tv_usec = 0;
       
    74 
       
    75         setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
       
    76         setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
       
    77     }
       
    78     return (jint)fd;
       
    79 }
       
    80 
       
    81 /*
       
    82  * Class:     sun_tools_attach_AixVirtualMachine
       
    83  * Method:    connect
       
    84  * Signature: (ILjava/lang/String;)I
       
    85  */
       
    86 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_connect
       
    87   (JNIEnv *env, jclass cls, jint fd, jstring path)
       
    88 {
       
    89     jboolean isCopy;
       
    90     const char* p = GetStringPlatformChars(env, path, &isCopy);
       
    91     if (p != NULL) {
       
    92         struct sockaddr_un addr;
       
    93         int err = 0;
       
    94 
       
    95         memset(&addr, 0, sizeof(addr));
       
    96         addr.sun_family = AF_UNIX;
       
    97         /* strncpy is safe because addr.sun_path was zero-initialized before. */
       
    98         strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);
       
    99         /* We must call bind with the actual socketaddr length. This is obligatory for AS400. */
       
   100         if (connect(fd, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
       
   101             err = errno;
       
   102         }
       
   103 
       
   104         if (isCopy) {
       
   105             JNU_ReleaseStringPlatformChars(env, path, p);
       
   106         }
       
   107 
       
   108         /*
       
   109          * If the connect failed then we throw the appropriate exception
       
   110          * here (can't throw it before releasing the string as can't call
       
   111          * JNI with pending exception)
       
   112          */
       
   113         if (err != 0) {
       
   114             if (err == ENOENT) {
       
   115                 JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
       
   116             } else {
       
   117                 char* msg = strdup(strerror(err));
       
   118                 JNU_ThrowIOException(env, msg);
       
   119                 if (msg != NULL) {
       
   120                     free(msg);
       
   121                 }
       
   122             }
       
   123         }
       
   124     }
       
   125 }
       
   126 
       
   127 
       
   128 /*
       
   129  * Structure and callback function used to send a QUIT signal to all
       
   130  * children of a given process
       
   131  */
       
   132 typedef struct {
       
   133     pid_t ppid;
       
   134 } SendQuitContext;
       
   135 
       
   136 static void SendQuitCallback(const pid_t pid, void* user_data) {
       
   137     SendQuitContext* context = (SendQuitContext*)user_data;
       
   138     pid_t parent = getParent(pid);
       
   139     if (parent == context->ppid) {
       
   140         kill(pid, SIGQUIT);
       
   141     }
       
   142 }
       
   143 
       
   144 /*
       
   145  * Class:     sun_tools_attach_AixVirtualMachine
       
   146  * Method:    sendQuitTo
       
   147  * Signature: (I)V
       
   148  */
       
   149 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_sendQuitTo
       
   150   (JNIEnv *env, jclass cls, jint pid)
       
   151 {
       
   152     if (kill((pid_t)pid, SIGQUIT)) {
       
   153         JNU_ThrowIOExceptionWithLastError(env, "kill");
       
   154     }
       
   155 }
       
   156 
       
   157 /*
       
   158  * Class:     sun_tools_attach_AixVirtualMachine
       
   159  * Method:    checkPermissions
       
   160  * Signature: (Ljava/lang/String;)V
       
   161  */
       
   162 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_checkPermissions
       
   163   (JNIEnv *env, jclass cls, jstring path)
       
   164 {
       
   165     jboolean isCopy;
       
   166     const char* p = GetStringPlatformChars(env, path, &isCopy);
       
   167     if (p != NULL) {
       
   168         struct stat64 sb;
       
   169         uid_t uid, gid;
       
   170         int res;
       
   171         /* added missing initialization of the stat64 buffer */
       
   172         memset(&sb, 0, sizeof(struct stat64));
       
   173 
       
   174         /*
       
   175          * Check that the path is owned by the effective uid/gid of this
       
   176          * process. Also check that group/other access is not allowed.
       
   177          */
       
   178         uid = geteuid();
       
   179         gid = getegid();
       
   180 
       
   181         res = stat64(p, &sb);
       
   182         if (res != 0) {
       
   183             /* save errno */
       
   184             res = errno;
       
   185         }
       
   186 
       
   187         /* release p here before we throw an I/O exception */
       
   188         if (isCopy) {
       
   189             JNU_ReleaseStringPlatformChars(env, path, p);
       
   190         }
       
   191 
       
   192         if (res == 0) {
       
   193             if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
       
   194                  ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
       
   195                 JNU_ThrowIOException(env, "well-known file is not secure");
       
   196             }
       
   197         } else {
       
   198             char* msg = strdup(strerror(res));
       
   199             JNU_ThrowIOException(env, msg);
       
   200             if (msg != NULL) {
       
   201                 free(msg);
       
   202             }
       
   203         }
       
   204     }
       
   205 }
       
   206 
       
   207 /*
       
   208  * Class:     sun_tools_attach_AixVirtualMachine
       
   209  * Method:    close
       
   210  * Signature: (I)V
       
   211  */
       
   212 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_close
       
   213   (JNIEnv *env, jclass cls, jint fd)
       
   214 {
       
   215     int res;
       
   216     /* Fixed deadlock when this call of close by the client is not seen by the attach server
       
   217      * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte,
       
   218      * because the close is lost without shutdown.
       
   219      */
       
   220     shutdown(fd, 2);
       
   221     RESTARTABLE(close(fd), res);
       
   222 }
       
   223 
       
   224 /*
       
   225  * Class:     sun_tools_attach_AixVirtualMachine
       
   226  * Method:    read
       
   227  * Signature: (I[BI)I
       
   228  */
       
   229 JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_read
       
   230   (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
       
   231 {
       
   232     unsigned char buf[128];
       
   233     size_t len = sizeof(buf);
       
   234     ssize_t n;
       
   235 
       
   236     size_t remaining = (size_t)(baLen - off);
       
   237     if (len > remaining) {
       
   238         len = remaining;
       
   239     }
       
   240 
       
   241     RESTARTABLE(read(fd, buf+off, len), n);
       
   242     if (n == -1) {
       
   243         JNU_ThrowIOExceptionWithLastError(env, "read");
       
   244     } else {
       
   245         if (n == 0) {
       
   246             n = -1;     // EOF
       
   247         } else {
       
   248             (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off));
       
   249         }
       
   250     }
       
   251     return n;
       
   252 }
       
   253 
       
   254 /*
       
   255  * Class:     sun_tools_attach_AixVirtualMachine
       
   256  * Method:    write
       
   257  * Signature: (I[B)V
       
   258  */
       
   259 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_write
       
   260   (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)
       
   261 {
       
   262     size_t remaining = bufLen;
       
   263     do {
       
   264         unsigned char buf[128];
       
   265         size_t len = sizeof(buf);
       
   266         int n;
       
   267 
       
   268         if (len > remaining) {
       
   269             len = remaining;
       
   270         }
       
   271         (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);
       
   272 
       
   273         RESTARTABLE(write(fd, buf, len), n);
       
   274         if (n > 0) {
       
   275             off += n;
       
   276             remaining -= n;
       
   277         } else {
       
   278             JNU_ThrowIOExceptionWithLastError(env, "write");
       
   279             return;
       
   280         }
       
   281 
       
   282     } while (remaining > 0);
       
   283 }