1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @modules java.base/jdk.internal.misc 27 */ 28 29 import java.io.File; 30 import java.io.FileOutputStream; 31 import java.lang.invoke.MethodHandles; 32 import java.nicl.*; 33 import java.nicl.types.*; 34 import java.nicl.metadata.*; 35 36 public class UnixSystem { 37 @NativeHeader 38 static interface system { 39 @C(file="dummy", line=1, column=1, USR="c:@F@getpid") 40 @NativeType(layout="()i", ctype="dummy", size=1) 41 @CallingConvention(value=1) 42 public abstract int getpid(); 43 44 @C(file="dummy", line=1, column=1, USR="c:@F@snprintf") 45 @NativeType(layout="(p:clp:c*)i", ctype="dummy", size=1) 46 @CallingConvention(value=1) 47 public abstract int snprintf(Pointer<Byte> buf, long size, Pointer<Byte> fmt, Object... args); 48 49 @C(file="dummy", line=1, column=1, USR="c:@F@strerror") 50 @NativeType(layout="(i)p:c", ctype="dummy", size=1) 51 @CallingConvention(value=1) 52 public abstract Pointer<Byte> strerror(int errno); 53 54 @C(file="dummy", line=1, column=1, USR="c:@errno") 55 @NativeType(layout="i", ctype="dummy", size=4) 56 public abstract int errno$get(); 57 58 @C(file="dummy", line=1, column=1, USR="c:@environ") 59 @NativeType(layout="p:p:V", ctype="dummy", size=8, name="environ") 60 public abstract Pointer<Pointer<Byte>> environ$get(); 61 62 public abstract Pointer<Pointer<Pointer<Byte>>> environ$ptr(); 63 } 64 65 @NativeHeader 66 static interface LinuxSystem { 67 @C(file="dummy", line=1, column=1, USR="c:@F@__xstat") 68 @NativeType(layout="(ip:cp:[iiiiiiiiiiiii])i", ctype="dummy", size=1) 69 @CallingConvention(value=1) 70 public abstract int __xstat(int ver, Pointer<Byte> path, Pointer<stat> buf); 71 72 @NativeType(layout="[iiiiiiiiiiiii]", ctype="dummy", size=144, isRecordType=true) 73 @C(file="dummy", line=47, column=11, USR="C:@S@MyStruct") 74 static interface stat extends Struct<stat> { 75 @Offset(offset=384l) 76 @C(file="dummy", line=47, column=11, USR="c:@SA@stat@st_size") 77 @NativeType(layout="i", ctype="off_t", size=4l) 78 int st_size$get(); 79 void st_size$set(int i); 80 } 81 } 82 83 @NativeHeader 84 static interface MacOSXSystem { 85 @C(file="dummy", line=1, column=1, USR="c:@F@stat") 86 @NativeType(layout="(p:cp:[iSSQIIi[ll][ll][ll][ll]qqiIIi2q])i", ctype="dummy", size=1) 87 @CallingConvention(value=1) 88 public abstract int stat$INODE64(Pointer<Byte> path, Pointer<stat> buf); 89 90 91 @NativeType(layout="[iSSQIIi[ll][ll][ll][ll]qqiIIi2q]", ctype="dummy", size=144, isRecordType=true) 92 @C(file="dummy", line=47, column=11, USR="C:@S@MyStruct") 93 static interface stat extends Struct<stat> { 94 @Offset(offset=768l) 95 @C(file="dummy", line=47, column=11, USR="c:@SA@stat@st_size") 96 @NativeType(layout="l", ctype="off_t", size=4l) 97 long st_size$get(); 98 void st_size$set(long i); 99 } 100 } 101 102 private static final String OS = System.getProperty("os.name"); 103 104 public void testGetpid() { 105 system i = Libraries.bind(MethodHandles.lookup(), system.class); 106 107 long actual = i.getpid(); 108 long expected = ProcessHandle.current().pid(); 109 110 if (actual != expected) { 111 throw new RuntimeException("Actual pid: " + actual + " does not match expected pid: " + expected); 112 } 113 } 114 115 private static String lowerAndSprintf(system i, String fmt, Object... args) { 116 System.err.println("lowerAndSprintf fmt=" + fmt); 117 try (Scope scope = Scope.newNativeScope()) { 118 long bufSize = 128; 119 120 LayoutType<Byte> t = NativeTypes.UINT8; 121 Pointer<Byte> buf = scope.allocate(t, bufSize); 122 Pointer<Byte> cfmt = scope.toCString(fmt); 123 124 int n = i.snprintf(buf, bufSize, cfmt, args); 125 if (n >= bufSize) { 126 throw new IndexOutOfBoundsException(n); 127 } 128 129 return Pointer.toString(buf); 130 } 131 } 132 133 public void testPrintf() { 134 system i = Libraries.bind(MethodHandles.lookup(), system.class); 135 136 int n; 137 138 assertEquals("foo", lowerAndSprintf(i, "foo")); 139 assertEquals("foo: 4711", lowerAndSprintf(i, "foo: %d", 4711)); 140 assertEquals("foo: 47 11", lowerAndSprintf(i, "foo: %d %d", 47, 11)); 141 try (Scope scope = Scope.newNativeScope()) { 142 assertEquals("foo: bar", lowerAndSprintf(i, "foo: %s", scope.toCString("bar"))); 143 assertEquals("foo: bar baz", lowerAndSprintf(i, "foo: %s %s", scope.toCString("bar"), scope.toCString("baz"))); 144 } 145 } 146 147 private int getSizeUsingStat(String path) throws Exception { 148 switch (OS) { 149 case "Linux": 150 return getSizeUsingStat_Linux(path); 151 case "Mac OS X": 152 return getSizeUsingStat_MacOSX(path); 153 default: 154 // FIXME: Add other operating systems here... 155 throw new UnsupportedOperationException(OS + " not supported (yet)"); 156 } 157 } 158 159 private int getSizeUsingStat_Linux(String path) throws Exception { 160 LinuxSystem i = Libraries.bind(MethodHandles.lookup(), LinuxSystem.class); 161 162 try (Scope scope = Scope.newNativeScope()) { 163 LinuxSystem.stat s = scope.allocateStruct(LinuxSystem.stat.class); 164 Pointer<LinuxSystem.stat> p = s.ptr(); 165 166 s = p.get(); 167 168 int res = i.__xstat(1, scope.toCString(path), p); 169 if (res != 0) { 170 throwErrnoException("Call to __xstat failed"); 171 } 172 173 return s.st_size$get(); 174 } 175 } 176 177 private int getSizeUsingStat_MacOSX(String path) throws Exception { 178 MacOSXSystem i = Libraries.bind(MethodHandles.lookup(), MacOSXSystem.class); 179 180 try (Scope scope = Scope.newNativeScope()) { 181 MacOSXSystem.stat s = scope.allocateStruct(MacOSXSystem.stat.class); 182 Pointer<MacOSXSystem.stat> p = s.ptr(); 183 184 s = p.get(); 185 186 int res = i.stat$INODE64(scope.toCString(path), p); 187 if (res != 0) { 188 throwErrnoException("Call to stat failed"); 189 } 190 191 return (int)s.st_size$get(); 192 } 193 } 194 195 private static void throwErrnoException(String msg) { 196 try { 197 system sys = Libraries.bind(MethodHandles.lookup(), system.class); 198 Pointer<Byte> p = sys.strerror(sys.errno$get()); 199 throw new Exception(msg + ": " + Pointer.toString(p)); 200 } catch (Throwable t) { 201 throw new RuntimeException(t); 202 } 203 } 204 205 public void testStat() { 206 system i = Libraries.bind(MethodHandles.lookup(), system.class); 207 208 int nBytes = 4711; 209 210 try { 211 File f = File.createTempFile("stat_test", null); 212 FileOutputStream fos = new FileOutputStream(f); 213 fos.write(new byte[nBytes]); 214 fos.close(); 215 216 try { 217 assertEquals(nBytes, getSizeUsingStat(f.getPath())); 218 } finally { 219 f.delete(); 220 } 221 } catch (Exception e) { 222 throw new RuntimeException(e); 223 } 224 225 try { 226 int size = getSizeUsingStat("__surely_this___file_does_NOT_exist.txt"); 227 throw new RuntimeException("stat unexpectedly succeeded"); 228 } catch (Exception e) { 229 // expected 230 } 231 } 232 233 234 public void testEnviron() { 235 system i = Libraries.bind(MethodHandles.lookup(), system.class); 236 237 { 238 // Pointer version 239 Pointer<Pointer<Byte>> pp = i.environ$get().cast(NativeTypes.UINT8.pointer()); 240 Pointer<Byte> sp = pp.get(); 241 System.out.println("testEnviron.str: " + Pointer.toString(sp)); 242 } 243 244 { 245 // Reference version 246 Pointer<Pointer<Pointer<Byte>>> r = i.environ$ptr(); 247 Pointer<Pointer<Byte>> spp = r.get().cast(NativeTypes.UINT8.pointer()); 248 Pointer<Byte> sp = spp.get().cast(NativeTypes.UINT8); 249 } 250 } 251 252 private static void assertEquals(long expected, long actual) { 253 if (expected != actual) { 254 throw new RuntimeException("actual: " + actual + " does not match expected: " + expected); 255 } 256 } 257 258 private static void assertEquals(String expected, String actual) { 259 if (!expected.equals(actual)) { 260 throw new RuntimeException("actual: " + actual + " does not match expected: " + expected); 261 } 262 } 263 264 public static void main(String[] args) { 265 UnixSystem us = new UnixSystem(); 266 267 us.testGetpid(); 268 us.testPrintf(); 269 us.testStat(); 270 us.testEnviron(); 271 } 272 } --- EOF ---