Пример #1
0
    @Override
    public void output(int id, String line) {
      // general check if line contains file
      if (line.contains(fileName)) {

        // try to match line exactly
        try {
          Matcher permissionMatcher = permissionPattern.matcher(line);
          if (permissionMatcher.find()) {
            permissions = convertPermissions(permissionMatcher.group(1));

            Log.d(RootCommands.TAG, "Found permissions: " + permissions);
          } else {
            Log.d(RootCommands.TAG, "Permissions were not found in ls command!");
          }

          // try to parse for symlink
          Matcher symlinkMatcher = symlinkPattern.matcher(line);
          if (symlinkMatcher.find()) {
            /*
             * TODO: If symlink points to a file in the same directory the path is not
             * absolute!!!
             */
            symlink = symlinkMatcher.group(1);
            Log.d(RootCommands.TAG, "Symlink found: " + symlink);
          } else {
            Log.d(RootCommands.TAG, "No symlink found!");
          }
        } catch (Exception e) {
          Log.e(RootCommands.TAG, "Error with regex!", e);
        }
      }
    }
Пример #2
0
  /**
   * Copys a file to a destination. Because cp is not available on all android devices, we use dd or
   * cat.
   *
   * @param source example: /data/data/org.adaway/files/hosts
   * @param destination example: /system/etc/hosts
   * @param remountAsRw remounts the destination as read/write before writing to it
   * @param preservePermissions tries to copy file attributes from source to destination, if only
   *     cat is available only permissions are preserved
   * @return true if it was successfully copied
   * @throws BrokenBusyboxException
   * @throws IOException
   * @throws TimeoutException
   */
  public void copyFile(
      File source, File destination, boolean remountAsRw, boolean preservePermissions)
      throws FailedExecuteCommand, FileNotFoundException, IOException {

    /*
     * dd can only copy files, but we can not check if the source is a file without invoking
     * shell commands, because from Java we probably have no read access, thus we only check if
     * they are ending with trailing slashes
     */
    if (source.isDirectory() || destination.isDirectory()) {
      throw new FileNotFoundException("dd can only copy files!");
    }

    // remount destination as read/write before copying to it
    if (remountAsRw) {
      if (!remount(destination, "RW")) {
        Log.d(
            RootCommands.TAG,
            "Remounting failed! There is probably no need to remount this partition!");
      }
    }

    // get permissions of source before overwriting
    String permissions = null;
    if (preservePermissions) {
      permissions = getFilePermissions(source.getAbsolutePath());
    }

    try {
      shell.execCommand("toolbox dd if=" + source + " of=" + destination);
    } catch (FailedExecuteCommand e) {
      shell.execCommand("toolbox cat " + source + " > " + destination);
    }

    // set back permissions from source to destination
    if (preservePermissions) {
      setFilePermissions(destination, permissions);
    }

    // remount destination back to read only
    if (remountAsRw) {
      if (!remount(destination, "RO")) {
        Log.d(
            RootCommands.TAG,
            "Remounting failed! There is probably no need to remount this partition!");
      }
    }
  }
Пример #3
0
    public LsCommand(String file) {
      super("toolbox ls -l " + file);

      // get only filename:
      this.fileName = (new File(file)).getName();
      Log.d(RootCommands.TAG, "fileName: " + fileName);

      /**
       * regex to get pid out of ps line, example:
       *
       * <pre>
       * with busybox:
       *     lrwxrwxrwx     1 root root            15 Aug 13 12:14 dev/stdin -> /proc/self/fd/0
       *
       * with toolbox:
       *     lrwxrwxrwx root root            15 Aug 13 12:14 stdin -> /proc/self/fd/0
       *
       * Regex:
       * ^.*?(\\S{10})                     .*                                                  $
       * </pre>
       */
      permissionRegex = "^.*?(\\S{10}).*$";
      permissionPattern = Pattern.compile(permissionRegex);

      /**
       * regex to get symlink
       *
       * <pre>
       *     ->           /proc/self/fd/0
       * ^.*?\\-\\> \\s+  (.*)           $
       * </pre>
       */
      symlinkRegex = "^.*?\\-\\>\\s+(.*)$";
      symlinkPattern = Pattern.compile(symlinkRegex);
    }
Пример #4
0
  /**
   * This will return an ArrayList of the class Mount. The class mount contains the following
   * property's: device mountPoint type flags
   *
   * <p>These will provide you with any information you need to work with the mount points.
   *
   * @return <code>ArrayList<Mount></code> an ArrayList of the class Mount.
   * @throws Exception if we cannot return the mount points.
   */
  protected static ArrayList<Mount> getMounts() throws Exception {

    final String tempFile = "/data/local/RootToolsMounts";

    // copy /proc/mounts to tempfile. Directly reading it does not work on 4.3
    Shell shell = Shell.startRootShell();
    Toolbox tb = new Toolbox(shell);
    tb.copyFile("/proc/mounts", tempFile, false, false);
    tb.setFilePermissions(tempFile, "777");
    shell.close();

    LineNumberReader lnr = null;
    lnr = new LineNumberReader(new FileReader(tempFile));
    String line;
    ArrayList<Mount> mounts = new ArrayList<Mount>();
    while ((line = lnr.readLine()) != null) {

      Log.d(RootCommands.TAG, line);

      String[] fields = line.split(" ");
      mounts.add(
          new Mount(
              new File(fields[0]), // device
              new File(fields[1]), // mountPoint
              fields[2], // fstype
              fields[3] // flags
              ));
    }
    lnr.close();

    return mounts;
  }
Пример #5
0
  /**
   * @param file String that represent the file, including the full path to the file and its name.
   * @return File permissions as String, for example: 777, returns null on error
   * @throws IOException
   * @throws TimeoutException
   * @throws BrokenBusyboxException
   */
  public String getFilePermissions(String file)
      throws FailedExecuteCommand, BrokenBusyboxException, IOException {
    Log.d(RootCommands.TAG, "Checking permissions for " + file);

    String permissions = null;

    if (fileExists(file)) {
      Log.d(RootCommands.TAG, file + " was found.");

      LsCommand lsCommand = new LsCommand(file);

      shell.execCommand(lsCommand);

      permissions = lsCommand.getPermissions();
    }

    return permissions;
  }
Пример #6
0
  /**
   * This method can be used to kill a running process
   *
   * <p>(commands: ps, kill)
   *
   * @param processName name of process to kill
   * @return <code>true</code> if process was found and killed successfully
   * @throws IOException
   * @throws TimeoutException
   * @throws BrokenBusyboxException
   */
  public boolean killAll(String processName)
      throws FailedExecuteCommand, TimeoutException, IOException {
    Log.d(RootCommands.TAG, "Killing process " + processName);

    PsCommand psCommand = new PsCommand(processName);

    shell.execCommand(psCommand);

    // kill processes
    if (!psCommand.getPids().isEmpty()) {
      // example: kill -9 1234 1222 5343
      SimpleCommand killCommand = new SimpleCommand("toolbox kill -9 " + psCommand.getPidsString());
      shell.execCommand(killCommand);

      return killCommand.getExitCode() == 0;
    } else {
      Log.d(RootCommands.TAG, "No pid found! Nothing was killed!");
      return false;
    }
  }
Пример #7
0
    @Override
    public void output(int id, String line) {
      // general check if line contains processName
      if (line.contains(processName)) {
        Matcher psMatcher = psPattern.matcher(line);

        // try to match line exactly
        try {
          if (psMatcher.find()) {
            String pid = psMatcher.group(1);
            // add to pids list
            pids.add(pid);
            Log.d(RootCommands.TAG, "Found pid: " + pid);
          } else {
            Log.d(RootCommands.TAG, "Matching in ps command failed!");
          }
        } catch (Exception e) {
          Log.e(RootCommands.TAG, "Error with regex!", e);
        }
      }
    }
Пример #8
0
 /**
  * This will tell you how the specified mount is mounted. rw, ro, etc...
  *
  * @param path The mount you want to check
  * @return <code>String</code> What the mount is mounted as.
  * @throws Exception if we cannot determine how the mount is mounted.
  */
 public String getMountedAs(String path) throws Exception {
   ArrayList<Mount> mounts = Remounter.getMounts();
   if (mounts != null) {
     for (Mount mount : mounts) {
       if (path.contains(mount.getMountPoint().getAbsolutePath())) {
         Log.d(RootCommands.TAG, (String) mount.getFlags().toArray()[0]);
         return (String) mount.getFlags().toArray()[0];
       }
     }
   }
   throw new Exception();
 }
Пример #9
0
  /**
   * This will return a String that represent the symlink for a specified file.
   *
   * @param file The path to the file to get the Symlink for. (must have absolute path)
   * @return A String that represent the symlink for a specified file or null if no symlink exists.
   * @throws IOException
   * @throws TimeoutException
   * @throws BrokenBusyboxException
   */
  public String getSymlink(String file) throws FailedExecuteCommand, TimeoutException, IOException {
    Log.d(RootCommands.TAG, "Find symlink for " + file);

    String symlink;

    LsCommand lsCommand = new LsCommand(file);
    shell.execCommand(lsCommand);

    symlink = lsCommand.getSymlink();

    return symlink;
  }
Пример #10
0
  /**
   * Check if there is enough space on partition where target is located
   *
   * @param size size of file to put on partition
   * @param target path where to put the file
   * @return true if it will fit on partition of target, false if it will not fit.
   */
  public boolean hasEnoughSpaceOnPartition(String target, long size) {
    try {
      // new File(target).getFreeSpace() (API 9) is not working on data partition

      // get directory without file
      String directory = new File(target).getParent();

      StatFs stat = new StatFs(directory);
      long blockSize = stat.getBlockSize();
      long availableBlocks = stat.getAvailableBlocks();
      long availableSpace = availableBlocks * blockSize;

      Log.i(
          RootCommands.TAG,
          "Checking for enough space: Target: "
              + target
              + ", directory: "
              + directory
              + " size: "
              + size
              + ", availableSpace: "
              + availableSpace);

      if (size < availableSpace) {
        return true;
      } else {
        Log.e(RootCommands.TAG, "Not enough space on partition!");
        return false;
      }
    } catch (Exception e) {
      // if new StatFs(directory) fails catch IllegalArgumentException and just return true as
      // workaround
      Log.e(RootCommands.TAG, "Problem while getting available space on partition!", e);
      return true;
    }
  }
Пример #11
0
 private Mount findMountPointRecursive(String file) {
   try {
     ArrayList<Mount> mounts = getMounts();
     for (File path = new File(file); path != null; ) {
       for (Mount mount : mounts) {
         if (mount.getMountPoint().equals(path)) {
           return mount;
         }
       }
     }
     return null;
   } catch (IOException e) {
     throw new RuntimeException(e);
   } catch (Exception e) {
     Log.e(RootCommands.TAG, "Exception", e);
   }
   return null;
 }
Пример #12
0
  public void setFilePermissions(File file, String permissions) throws FailedExecuteCommand {
    Log.d(RootCommands.TAG, "Set permissions of " + file + " to " + permissions);

    shell.execCommand("toolbox chmod " + permissions + " \"" + file + "\"");
  }
Пример #13
0
  /**
   * This will take a path, which can contain the file name as well, and attempt to remount the
   * underlying partition.
   *
   * <p>For example, passing in the following string:
   * "/system/bin/some/directory/that/really/would/never/exist" will result in /system ultimately
   * being remounted. However, keep in mind that the longer the path you supply, the more work this
   * has to do, and the slower it will run.
   *
   * @param file file path
   * @param mountType mount type: pass in RO (Read only) or RW (Read Write)
   * @return a <code>boolean</code> which indicates whether or not the partition has been remounted
   *     as specified.
   */
  protected boolean remount(String file, String mountType) {

    // if the path has a trailing slash get rid of it.
    if (file.endsWith("/") && !file.equals("/")) {
      file = file.substring(0, file.lastIndexOf("/"));
    }
    // Make sure that what we are trying to remount is in the mount list.
    boolean foundMount = false;
    while (!foundMount) {
      try {
        for (Mount mount : getMounts()) {
          Log.d(RootCommands.TAG, mount.getMountPoint().toString());

          if (file.equals(mount.getMountPoint().toString())) {
            foundMount = true;
            break;
          }
        }
      } catch (Exception e) {
        Log.e(RootCommands.TAG, "Exception", e);
        return false;
      }
      if (!foundMount) {
        try {
          file = (new File(file).getParent()).toString();
        } catch (Exception e) {
          Log.e(RootCommands.TAG, "Exception", e);
          return false;
        }
      }
    }
    Mount mountPoint = findMountPointRecursive(file);

    Log.d(
        RootCommands.TAG,
        "Remounting "
            + mountPoint.getMountPoint().getAbsolutePath()
            + " as "
            + mountType.toLowerCase(Locale.US));
    final boolean isMountMode = mountPoint.getFlags().contains(mountType.toLowerCase(Locale.US));

    if (!isMountMode) {
      // grab an instance of the internal class
      try {
        SimpleCommand command =
            new SimpleCommand(
                "busybox mount -o remount,"
                    + mountType.toLowerCase(Locale.US)
                    + " "
                    + mountPoint.getDevice().getAbsolutePath()
                    + " "
                    + mountPoint.getMountPoint().getAbsolutePath(),
                "toolbox mount -o remount,"
                    + mountType.toLowerCase(Locale.US)
                    + " "
                    + mountPoint.getDevice().getAbsolutePath()
                    + " "
                    + mountPoint.getMountPoint().getAbsolutePath(),
                "mount -o remount,"
                    + mountType.toLowerCase(Locale.US)
                    + " "
                    + mountPoint.getDevice().getAbsolutePath()
                    + " "
                    + mountPoint.getMountPoint().getAbsolutePath(),
                "/system/bin/toolbox mount -o remount,"
                    + mountType.toLowerCase(Locale.US)
                    + " "
                    + mountPoint.getDevice().getAbsolutePath()
                    + " "
                    + mountPoint.getMountPoint().getAbsolutePath());

        // execute on shell
        shell.add(command).waitForFinish();

      } catch (Exception e) {
      }

      mountPoint = findMountPointRecursive(file);
    }

    if (mountPoint != null) {
      Log.d(RootCommands.TAG, mountPoint.getFlags() + " AND " + mountType.toLowerCase(Locale.US));
      if (mountPoint.getFlags().contains(mountType.toLowerCase(Locale.US))) {
        Log.d(RootCommands.TAG, mountPoint.getFlags().toString());
        return true;
      } else {
        Log.d(RootCommands.TAG, mountPoint.getFlags().toString());
      }
    } else {
      Log.d(RootCommands.TAG, "mountPoint is null");
    }
    return false;
  }