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