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 @NativeLocation(file="dummy", line=1, column=1, USR="c:@F@getpid") 40 @NativeType(layout="()i", ctype="dummy") 41 public abstract int getpid(); 42 43 @NativeLocation(file="dummy", line=1, column=1, USR="c:@F@snprintf") 44 @NativeType(layout="(p:clp:c*)i", ctype="dummy") 45 public abstract int snprintf(Pointer<Byte> buf, long size, Pointer<Byte> fmt, Object... args); 46 47 @NativeLocation(file="dummy", line=1, column=1, USR="c:@F@strerror") 48 @NativeType(layout="(i)p:c", ctype="dummy") 49 public abstract Pointer<Byte> strerror(int errno); 50 51 @NativeLocation(file="dummy", line=1, column=1, USR="c:@errno") 52 @NativeType(layout="i", ctype="dummy") 53 public abstract int errno$get(); 54 55 @NativeLocation(file="dummy", line=1, column=1, USR="c:@environ") 56 @NativeType(layout="p:p:V", ctype="dummy", name="environ") 57 public abstract Pointer<Pointer<Byte>> environ$get(); 58 59 public abstract Pointer<Pointer<Pointer<Byte>>> environ$ptr(); 60 } 61 62 @NativeHeader 63 static interface LinuxSystem { 64 @NativeLocation(file="dummy", line=1, column=1, USR="c:@F@__xstat") 65 @NativeType(layout="(ip:cp:[iiiiiiiiiiiii])i", ctype="dummy") 66 public abstract int __xstat(int ver, Pointer<Byte> path, Pointer<stat> buf); 67 68 @NativeLocation(file="dummy", line=47, column=11, USR="C:@S@MyStruct") 69 @NativeStruct("[iiiiiiiiiiiii]") 70 static interface stat extends Struct<stat> { 71 @Offset(offset=384l) 72 @NativeLocation(file="dummy", line=47, column=11, USR="c:@SA@stat@st_size") 73 @NativeType(layout="i", ctype="off_t") 74 int st_size$get(); 75 void st_size$set(int i); 76 } 77 } 78 79 @NativeHeader 80 static interface MacOSXSystem { 81 @NativeLocation(file="dummy", line=1, column=1, USR="c:@F@stat") 82 @NativeType(layout="(p:cp:[iSSQIIi[ll][ll][ll][ll]qqiIIi2q])i", ctype="dummy") 83 public abstract int stat$INODE64(Pointer<Byte> path, Pointer<stat> buf); 84 85 86 @NativeLocation(file="dummy", line=47, column=11, USR="C:@S@MyStruct") 87 @NativeStruct("[iSSQIIi[ll][ll][ll][ll]qqiIIi2q]") 88 static interface stat extends Struct<stat> { 89 @Offset(offset=768l) 90 @NativeLocation(file="dummy", line=47, column=11, USR="c:@SA@stat@st_size") 91 @NativeType(layout="l", ctype="off_t") 92 long st_size$get(); 93 void st_size$set(long i); 94 } 95 } 96 97 private static final String OS = System.getProperty("os.name"); 98 99 public void testGetpid() { 100 system i = Libraries.bind(MethodHandles.lookup(), system.class); 101 102 long actual = i.getpid(); 103 long expected = ProcessHandle.current().pid(); 104 105 if (actual != expected) { 106 throw new RuntimeException("Actual pid: " + actual + " does not match expected pid: " + expected); 107 } 108 } 109 110 private static String lowerAndSprintf(system i, String fmt, Object... args) { 111 System.err.println("lowerAndSprintf fmt=" + fmt); 112 try (Scope scope = Scope.newNativeScope()) { 113 long bufSize = 128; 114 115 LayoutType<Byte> t = NativeTypes.UINT8; 116 Pointer<Byte> buf = scope.allocate(t, bufSize); 117 Pointer<Byte> cfmt = scope.toCString(fmt); 118 119 int n = i.snprintf(buf, bufSize, cfmt, args); 120 if (n >= bufSize) { 121 throw new IndexOutOfBoundsException(n); 122 } 123 124 return Pointer.toString(buf); 125 } 126 } 127 128 public void testPrintf() { 129 system i = Libraries.bind(MethodHandles.lookup(), system.class); 130 131 int n; 132 133 assertEquals("foo", lowerAndSprintf(i, "foo")); 134 assertEquals("foo: 4711", lowerAndSprintf(i, "foo: %d", 4711)); 135 assertEquals("foo: 47 11", lowerAndSprintf(i, "foo: %d %d", 47, 11)); 136 try (Scope scope = Scope.newNativeScope()) { 137 assertEquals("foo: bar", lowerAndSprintf(i, "foo: %s", scope.toCString("bar"))); 138 assertEquals("foo: bar baz", lowerAndSprintf(i, "foo: %s %s", scope.toCString("bar"), scope.toCString("baz"))); 139 } 140 } 141 142 private int getSizeUsingStat(String path) throws Exception { 143 switch (OS) { 144 case "Linux": 145 return getSizeUsingStat_Linux(path); 146 case "Mac OS X": 147 return getSizeUsingStat_MacOSX(path); 148 default: 149 // FIXME: Add other operating systems here... 150 throw new UnsupportedOperationException(OS + " not supported (yet)"); 151 } 152 } 153 154 private int getSizeUsingStat_Linux(String path) throws Exception { 155 LinuxSystem i = Libraries.bind(MethodHandles.lookup(), LinuxSystem.class); 156 157 try (Scope scope = Scope.newNativeScope()) { 158 LinuxSystem.stat s = scope.allocateStruct(LinuxSystem.stat.class); 159 Pointer<LinuxSystem.stat> p = s.ptr(); 160 161 s = p.get(); 162 163 int res = i.__xstat(1, scope.toCString(path), p); 164 if (res != 0) { 165 throwErrnoException("Call to __xstat failed"); 166 } 167 168 return s.st_size$get(); 169 } 170 } 171 172 private int getSizeUsingStat_MacOSX(String path) throws Exception { 173 MacOSXSystem i = Libraries.bind(MethodHandles.lookup(), MacOSXSystem.class); 174 175 try (Scope scope = Scope.newNativeScope()) { 176 MacOSXSystem.stat s = scope.allocateStruct(MacOSXSystem.stat.class); 177 Pointer<MacOSXSystem.stat> p = s.ptr(); 178 179 s = p.get(); 180 181 int res = i.stat$INODE64(scope.toCString(path), p); 182 if (res != 0) { 183 throwErrnoException("Call to stat failed"); 184 } 185 186 return (int)s.st_size$get(); 187 } 188 } 189 190 private static void throwErrnoException(String msg) { 191 try { 192 system sys = Libraries.bind(MethodHandles.lookup(), system.class); 193 Pointer<Byte> p = sys.strerror(sys.errno$get()); 194 throw new Exception(msg + ": " + Pointer.toString(p)); 195 } catch (Throwable t) { 196 throw new RuntimeException(t); 197 } 198 } 199 200 public void testStat() { 201 system i = Libraries.bind(MethodHandles.lookup(), system.class); 202 203 int nBytes = 4711; 204 205 try { 206 File f = File.createTempFile("stat_test", null); 207 FileOutputStream fos = new FileOutputStream(f); 208 fos.write(new byte[nBytes]); 209 fos.close(); 210 211 try { 212 assertEquals(nBytes, getSizeUsingStat(f.getPath())); 213 } finally { 214 f.delete(); 215 } 216 } catch (Exception e) { 217 throw new RuntimeException(e); 218 } 219 220 try { 221 int size = getSizeUsingStat("__surely_this___file_does_NOT_exist.txt"); 222 throw new RuntimeException("stat unexpectedly succeeded"); 223 } catch (Exception e) { 224 // expected 225 } 226 } 227 228 229 public void testEnviron() { 230 system i = Libraries.bind(MethodHandles.lookup(), system.class); 231 232 { 233 // Pointer version 234 Pointer<Pointer<Byte>> pp = i.environ$get().cast(NativeTypes.UINT8.pointer()); 235 Pointer<Byte> sp = pp.get(); 236 System.out.println("testEnviron.str: " + Pointer.toString(sp)); 237 } 238 239 { 240 // Reference version 241 Pointer<Pointer<Pointer<Byte>>> r = i.environ$ptr(); 242 Pointer<Pointer<Byte>> spp = r.get().cast(NativeTypes.UINT8.pointer()); 243 Pointer<Byte> sp = spp.get().cast(NativeTypes.UINT8); 244 } 245 } 246 247 private static void assertEquals(long expected, long actual) { 248 if (expected != actual) { 249 throw new RuntimeException("actual: " + actual + " does not match expected: " + expected); 250 } 251 } 252 253 private static void assertEquals(String expected, String actual) { 254 if (!expected.equals(actual)) { 255 throw new RuntimeException("actual: " + actual + " does not match expected: " + expected); 256 } 257 } 258 259 public static void main(String[] args) { 260 UnixSystem us = new UnixSystem(); 261 262 us.testGetpid(); 263 us.testPrintf(); 264 us.testStat(); 265 us.testEnviron(); 266 } 267 } --- EOF ---