1 /* 2 * Copyright (c) 2020, Red Hat Inc. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.platform; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 import java.nio.file.Path; 31 import java.nio.file.Paths; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Optional; 35 import java.util.function.Function; 36 import java.util.stream.Stream; 37 38 /** 39 * Cgroup version agnostic controller logic 40 * 41 */ 42 public interface CgroupSubsystemController { 43 44 public static final String EMPTY_STR = ""; 45 46 public String path(); 47 48 /** 49 * getStringValue 50 * 51 * Return the first line of the file "param" argument from the controller. 52 * 53 * TODO: Consider using weak references for caching BufferedReader object. 54 * 55 * @param controller 56 * @param param 57 * @return Returns the contents of the file specified by param or null if 58 * an error occurs. 59 */ 60 public static String getStringValue(CgroupSubsystemController controller, String param) { 61 if (controller == null) return null; 62 63 try { 64 return CgroupUtil.readStringValue(controller, param); 65 } 66 catch (IOException e) { 67 return null; 68 } 69 70 } 71 72 /** 73 * Get an entry from file "param" within the "controller" directory path 74 * which matches string "match". Applies "conversion" to the matching line. 75 * 76 * @param controller 77 * @param param 78 * @param match 79 * @param conversion 80 * @param defaultRetval 81 * @return The long value as derived by applying "conversion" to the matching 82 * line or "defaultRetval" if there was an error or no match found. 83 */ 84 public static long getLongValueMatchingLine(CgroupSubsystemController controller, 85 String param, 86 String match, 87 Function<String, Long> conversion, 88 long defaultRetval) { 89 long retval = defaultRetval; 90 if (controller == null) { 91 return retval; 92 } 93 try { 94 Path filePath = Paths.get(controller.path(), param); 95 List<String> lines = CgroupUtil.readAllLinesPrivileged(filePath); 96 for (String line : lines) { 97 if (line.startsWith(match)) { 98 retval = conversion.apply(line); 99 break; 100 } 101 } 102 } catch (IOException e) { 103 // Ignore. Default is unlimited. 104 } 105 return retval; 106 } 107 108 /** 109 * Get a long value from directory "controller" and file "param", by 110 * applying "conversion" to the string value within the file. 111 * 112 * @param controller 113 * @param param 114 * @param conversion 115 * @param defaultRetval 116 * @return The converted long value or "defaultRetval" if there was an 117 * error. 118 */ 119 public static long getLongValue(CgroupSubsystemController controller, 120 String param, 121 Function<String, Long> conversion, 122 long defaultRetval) { 123 String strval = getStringValue(controller, param); 124 if (strval == null) return defaultRetval; 125 return conversion.apply(strval); 126 } 127 128 /** 129 * Get a double value from file "param" within "controller". 130 * 131 * @param controller 132 * @param param 133 * @param defaultRetval 134 * @return The double value or "defaultRetval" if there was an error. 135 */ 136 public static double getDoubleValue(CgroupSubsystemController controller, String param, double defaultRetval) { 137 String strval = getStringValue(controller, param); 138 139 if (strval == null) return defaultRetval; 140 141 double retval = Double.parseDouble(strval); 142 143 return retval; 144 } 145 146 /** 147 * getLongEntry 148 * 149 * Return the long value from the line containing the string "entryname" 150 * within file "param" in the "controller". 151 * 152 * TODO: Consider using weak references for caching BufferedReader object. 153 * 154 * @param controller 155 * @param param 156 * @param entryname 157 * @return long value or "defaultRetval" if there was an error or no match 158 * was found. 159 */ 160 public static long getLongEntry(CgroupSubsystemController controller, String param, String entryname, long defaultRetval) { 161 if (controller == null) return defaultRetval; 162 163 try (Stream<String> lines = CgroupUtil.readFilePrivileged(Paths.get(controller.path(), param))) { 164 165 Optional<String> result = lines.map(line -> line.split(" ")) 166 .filter(line -> (line.length == 2 && 167 line[0].equals(entryname))) 168 .map(line -> line[1]) 169 .findFirst(); 170 171 return result.isPresent() ? Long.parseLong(result.get()) : defaultRetval; 172 } 173 catch (IOException e) { 174 return defaultRetval; 175 } 176 } 177 178 /** 179 * stringRangeToIntArray 180 * 181 * Convert a string in the form of 1,3-4,6 to an array of 182 * integers containing all the numbers in the range. 183 * 184 * @param range 185 * @return int[] containing a sorted list of numbers as represented by 186 * the string range. Returns null if there was an error or the input 187 * was an empty string. 188 */ 189 public static int[] stringRangeToIntArray(String range) { 190 if (range == null || EMPTY_STR.equals(range)) return null; 191 192 ArrayList<Integer> results = new ArrayList<>(); 193 String strs[] = range.split(","); 194 for (String str : strs) { 195 if (str.contains("-")) { 196 String lohi[] = str.split("-"); 197 // validate format 198 if (lohi.length != 2) { 199 continue; 200 } 201 int lo = Integer.parseInt(lohi[0]); 202 int hi = Integer.parseInt(lohi[1]); 203 for (int i = lo; i <= hi; i++) { 204 results.add(i); 205 } 206 } 207 else { 208 results.add(Integer.parseInt(str)); 209 } 210 } 211 212 // sort results 213 results.sort(null); 214 215 // convert ArrayList to primitive int array 216 int[] ints = new int[results.size()]; 217 int i = 0; 218 for (Integer n : results) { 219 ints[i++] = n; 220 } 221 222 return ints; 223 } 224 225 /** 226 * Convert a number from its string representation to a long. 227 * 228 * @param strval 229 * @param overflowRetval 230 * @param defaultRetval 231 * @return The converted long value. "overflowRetval" is returned if the 232 * string representation exceeds the range of type long. 233 * "defaultRetval" is returned if another type of error occurred 234 * during conversion. 235 */ 236 public static long convertStringToLong(String strval, long overflowRetval, long defaultRetval) { 237 long retval = defaultRetval; 238 if (strval == null) return retval; 239 240 try { 241 retval = Long.parseLong(strval); 242 } catch (NumberFormatException e) { 243 // For some properties (e.g. memory.limit_in_bytes, cgroups v1) we may overflow 244 // the range of signed long. In this case, return overflowRetval 245 BigInteger b = new BigInteger(strval); 246 if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { 247 return overflowRetval; 248 } 249 } 250 return retval; 251 } 252 253 }