1 /*
   2  * Copyright (c) 2018, 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.  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.cgroupv1;
  27 
  28 import java.io.BufferedReader;
  29 import java.io.IOException;
  30 import java.math.BigInteger;
  31 import java.nio.file.Files;
  32 import java.nio.file.Path;
  33 import java.nio.file.Paths;
  34 import java.util.ArrayList;
  35 import java.util.Optional;
  36 import java.util.stream.Stream;
  37 
  38 public class SubSystem {
  39     String root;
  40     String mountPoint;
  41     String path;
  42 
  43     public SubSystem(String root, String mountPoint) {
  44         this.root = root;
  45         this.mountPoint = mountPoint;
  46     }
  47 
  48     public void setPath(String cgroupPath) {
  49         if (root != null && cgroupPath != null) {
  50             if (root.equals("/")) {
  51                 if (!cgroupPath.equals("/")) {
  52                     path = mountPoint + cgroupPath;
  53                 }
  54                 else {
  55                     path = mountPoint;
  56                 }
  57             }
  58             else {
  59                 if (root.equals(cgroupPath)) {
  60                     path = mountPoint;
  61                 }
  62                 else {
  63                     if (root.indexOf(cgroupPath) == 0) {
  64                         if (cgroupPath.length() > root.length()) {
  65                             String cgroupSubstr = cgroupPath.substring(root.length());
  66                             path = mountPoint + cgroupSubstr;
  67                         }
  68                     }
  69                 }
  70             }
  71         }
  72     }
  73 
  74     public String path() {
  75         return path;
  76     }
  77 
  78     /**
  79      * getSubSystemStringValue
  80      *
  81      * Return the first line of the file "parm" argument from the subsystem.
  82      *
  83      * TODO:  Consider using weak references for caching BufferedReader object.
  84      *
  85      * @param subsystem
  86      * @param parm
  87      * @return Returns the contents of the file specified by param.
  88      */
  89     public static String getStringValue(SubSystem subsystem, String parm) {
  90         if (subsystem == null) return null;
  91 
  92         try(BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(subsystem.path(), parm))) {
  93             String line = bufferedReader.readLine();
  94             return line;
  95         }
  96         catch (IOException e) {
  97             return null;
  98         }
  99 
 100     }
 101 
 102     public static long getLongValue(SubSystem subsystem, String parm) {
 103         String strval = getStringValue(subsystem, parm);
 104         long retval = 0;
 105 
 106         if (strval == null) return 0L;
 107 
 108         try {
 109             retval = Long.parseLong(strval);
 110         } catch (NumberFormatException e) {
 111             // For some properties (e.g. memory.limit_in_bytes) we may overflow the range of signed long.
 112             // In this case, return Long.max
 113             BigInteger b = new BigInteger(strval);
 114             if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
 115                 return Long.MAX_VALUE;
 116             }
 117         }
 118         return retval;
 119     }
 120 
 121     public static double getDoubleValue(SubSystem subsystem, String parm) {
 122         String strval = getStringValue(subsystem, parm);
 123 
 124         if (strval == null) return 0L;
 125 
 126         double retval = Double.parseDouble(strval);
 127 
 128         return retval;
 129     }
 130 
 131     /**
 132      * getSubSystemlongEntry
 133      *
 134      * Return the long value from the line containing the string "entryname"
 135      * within file "parm" in the "subsystem".
 136      *
 137      * TODO:  Consider using weak references for caching BufferedReader object.
 138      *
 139      * @param subsystem
 140      * @param parm
 141      * @param entryname
 142      * @return long value
 143      */
 144     public static long getLongEntry(SubSystem subsystem, String parm, String entryname) {
 145         String val = null;
 146 
 147         if (subsystem == null) return 0L;
 148 
 149         try (Stream<String> lines = Files.lines(Paths.get(subsystem.path(), parm))) {
 150 
 151             Optional<String> result = lines.map(line -> line.split(" "))
 152                                            .filter(line -> (line.length == 2 &&
 153                                                    line[0].equals(entryname)))
 154                                            .map(line -> line[1])
 155                                            .findFirst();
 156 
 157             return result.isPresent() ? Long.parseLong(result.get()) : 0L;
 158         }
 159         catch (IOException e) {
 160             return 0L;
 161         }
 162     }
 163 
 164     public static int getIntValue(SubSystem subsystem, String parm) {
 165         String val = getStringValue(subsystem, parm);
 166 
 167         if (val == null) return 0;
 168 
 169         return Integer.parseInt(val);
 170     }
 171 
 172     /**
 173      * StringRangeToIntArray
 174      *
 175      * Convert a string in the form of  1,3-4,6 to an array of
 176      * integers containing all the numbers in the range.
 177      *
 178      * @param range
 179      * @return int[] containing a sorted list of processors or memory nodes
 180      */
 181     public static int[] StringRangeToIntArray(String range) {
 182         int[] ints = new int[0];
 183 
 184         if (range == null) return ints;
 185 
 186         ArrayList<Integer> results = new ArrayList<>();
 187         String strs[] = range.split(",");
 188         for (String str : strs) {
 189             if (str.contains("-")) {
 190                 String lohi[] = str.split("-");
 191                 // validate format
 192                 if (lohi.length != 2) {
 193                     continue;
 194                 }
 195                 int lo = Integer.parseInt(lohi[0]);
 196                 int hi = Integer.parseInt(lohi[1]);
 197                 for (int i = lo; i <= hi; i++) {
 198                     results.add(i);
 199                 }
 200             }
 201             else {
 202                 results.add(Integer.parseInt(str));
 203             }
 204         }
 205 
 206         // sort results
 207         results.sort(null);
 208 
 209         // convert ArrayList to primitive int array
 210         ints = new int[results.size()];
 211         int i = 0;
 212         for (Integer n : results) {
 213             ints[i++] = n;
 214         }
 215 
 216         return ints;
 217     }
 218 }