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