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
37static jfieldID entry_name;
38static jfieldID entry_dir;
39static jfieldID entry_fstype;
40static jfieldID entry_options;
41
42static jclass entry_cls;
43
44/**
45 * Call this to throw an internal UnixException when a system/library
46 * call fails
47 */
48static 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 */
59JNIEXPORT void JNICALL
60Java_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 */
85JNIEXPORT jobjectArray JNICALL
86Java_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}
231