1 /*
   2  * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2013, 2019 SAP SE. 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 <stdlib.h>
  28 #include <string.h>
  29 #include <errno.h>
  30 #include <sys/types.h>
  31 #include <sys/mntctl.h>
  32 
  33 #include "jni.h"
  34 #include "jni_util.h"
  35 
  36 #include "sun_nio_fs_AixNativeDispatcher.h"
  37 
  38 static jfieldID entry_name;
  39 static jfieldID entry_dir;
  40 static jfieldID entry_fstype;
  41 static jfieldID entry_options;
  42 
  43 static jclass entry_cls;
  44 
  45 /**
  46  * Call this to throw an internal UnixException when a system/library
  47  * call fails
  48  */
  49 static void throwUnixException(JNIEnv* env, int errnum) {
  50     jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
  51         "(I)V", errnum);
  52     if (x != NULL) {
  53         (*env)->Throw(env, x);
  54     }
  55 }
  56 
  57 /**
  58  * Initialization
  59  */
  60 JNIEXPORT void JNICALL
  61 Java_sun_nio_fs_AixNativeDispatcher_init(JNIEnv* env, jclass this)
  62 {
  63     jclass clazz;
  64 
  65     clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
  66     CHECK_NULL(clazz);
  67     entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
  68     CHECK_NULL(entry_name);
  69     entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
  70     CHECK_NULL(entry_dir);
  71     entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
  72     CHECK_NULL(entry_fstype);
  73     entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
  74     CHECK_NULL(entry_options);
  75     entry_cls = (*env)->NewGlobalRef(env, clazz);
  76     if (entry_cls == NULL) {
  77         JNU_ThrowOutOfMemoryError(env, NULL);
  78         return;
  79     }
  80 }
  81 
  82 /**
  83  * Special implementation of getextmntent (see SolarisNativeDispatcher.c)
  84  * that returns all entries at once.
  85  */
  86 JNIEXPORT jobjectArray JNICALL
  87 Java_sun_nio_fs_AixNativeDispatcher_getmntctl(JNIEnv* env, jclass this)
  88 {
  89     int must_free_buf = 0;
  90     char stack_buf[1024];
  91     char* buffer = stack_buf;
  92     size_t buffer_size = 1024;
  93     int num_entries;
  94     int i;
  95     jobjectArray ret;
  96     struct vmount * vm;
  97 
  98     for (i = 0; i < 5; i++) {
  99         num_entries = mntctl(MCTL_QUERY, buffer_size, buffer);
 100         if (num_entries != 0) {
 101             break;
 102         }
 103         if (must_free_buf) {
 104             free(buffer);
 105         }
 106         buffer_size *= 8;
 107         buffer = malloc(buffer_size);
 108         must_free_buf = 1;
 109     }
 110     /* Treat zero entries like errors. */
 111     if (num_entries <= 0) {
 112         if (must_free_buf) {
 113             free(buffer);
 114         }
 115         throwUnixException(env, errno);
 116         return NULL;
 117     }
 118     ret = (*env)->NewObjectArray(env, num_entries, entry_cls, NULL);
 119     if (ret == NULL) {
 120         if (must_free_buf) {
 121             free(buffer);
 122         }
 123         return NULL;
 124     }
 125     vm = (struct vmount*)buffer;
 126     for (i = 0; i < num_entries; i++) {
 127         jsize len;
 128         jbyteArray bytes;
 129         const char* fstype;
 130         /* We set all relevant attributes so there is no need to call constructor. */
 131         jobject entry = (*env)->AllocObject(env, entry_cls);
 132         if (entry == NULL) {
 133             if (must_free_buf) {
 134                 free(buffer);
 135             }
 136             return NULL;
 137         }
 138         (*env)->SetObjectArrayElement(env, ret, i, entry);
 139 
 140         /* vm->vmt_data[...].vmt_size is 32 bit aligned and also includes NULL byte. */
 141         /* Since we only need the characters, it is necessary to check string size manually. */
 142         len = strlen((char*)vm + vm->vmt_data[VMT_OBJECT].vmt_off);
 143         bytes = (*env)->NewByteArray(env, len);
 144         if (bytes == NULL) {
 145             if (must_free_buf) {
 146                 free(buffer);
 147             }
 148             return NULL;
 149         }
 150         (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_OBJECT].vmt_off));
 151         (*env)->SetObjectField(env, entry, entry_name, bytes);
 152 
 153         len = strlen((char*)vm + vm->vmt_data[VMT_STUB].vmt_off);
 154         bytes = (*env)->NewByteArray(env, len);
 155         if (bytes == NULL) {
 156             if (must_free_buf) {
 157                 free(buffer);
 158             }
 159             return NULL;
 160         }
 161         (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_STUB].vmt_off));
 162         (*env)->SetObjectField(env, entry, entry_dir, bytes);
 163 
 164         switch (vm->vmt_gfstype) {
 165             case MNT_J2:
 166                 fstype = "jfs2";
 167                 break;
 168             case MNT_NAMEFS:
 169                 fstype = "namefs";
 170                 break;
 171             case MNT_NFS:
 172                 fstype = "nfs";
 173                 break;
 174             case MNT_JFS:
 175                 fstype = "jfs";
 176                 break;
 177             case MNT_CDROM:
 178                 fstype = "cdrom";
 179                 break;
 180             case MNT_PROCFS:
 181                 fstype = "procfs";
 182                 break;
 183             case MNT_NFS3:
 184                 fstype = "nfs3";
 185                 break;
 186             case MNT_AUTOFS:
 187                 fstype = "autofs";
 188                 break;
 189             case MNT_UDF:
 190                 fstype = "udfs";
 191                 break;
 192             case MNT_NFS4:
 193                 fstype = "nfs4";
 194                 break;
 195             case MNT_CIFS:
 196                 fstype = "smbfs";
 197                 break;
 198             default:
 199                 fstype = "unknown";
 200         }
 201         len = strlen(fstype);
 202         bytes = (*env)->NewByteArray(env, len);
 203         if (bytes == NULL) {
 204             if (must_free_buf) {
 205                 free(buffer);
 206             }
 207             return NULL;
 208         }
 209         (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
 210         (*env)->SetObjectField(env, entry, entry_fstype, bytes);
 211 
 212         len = strlen((char*)vm + vm->vmt_data[VMT_ARGS].vmt_off);
 213         bytes = (*env)->NewByteArray(env, len);
 214         if (bytes == NULL) {
 215             if (must_free_buf) {
 216                 free(buffer);
 217             }
 218             return NULL;
 219         }
 220         (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)((char *)vm + vm->vmt_data[VMT_ARGS].vmt_off));
 221         (*env)->SetObjectField(env, entry, entry_options, bytes);
 222 
 223         /* goto the next vmount structure: */
 224         vm = (struct vmount *)((char *)vm + vm->vmt_length);
 225     }
 226 
 227     if (must_free_buf) {
 228         free(buffer);
 229     }
 230     return ret;
 231 }