dom/system/gonk/OpenFileFinder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "OpenFileFinder.h"
     7 #include "mozilla/FileUtils.h"
     8 #include "nsPrintfCString.h"
    10 #include <sys/stat.h>
    11 #include <errno.h>
    13 #define USE_DEBUG 0
    15 #undef LOG
    16 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "OpenFileFinder", ## args)
    17 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "OpenFileFinder", ## args)
    18 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
    20 #if USE_DEBUG
    21 #define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
    22 #else
    23 #define DBG(args...)
    24 #endif
    26 namespace mozilla {
    27 namespace system {
    29 OpenFileFinder::OpenFileFinder(const nsACString& aPath,
    30                                bool aCheckIsB2gOrDescendant /* = true */)
    31   : mPath(aPath),
    32     mProcDir(nullptr),
    33     mFdDir(nullptr),
    34     mPid(0),
    35     mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant)
    36 {
    37   // We assume that we're running in the parent process
    38   mMyPid = getpid();
    39 }
    41 OpenFileFinder::~OpenFileFinder()
    42 {
    43   Close();
    44 }
    46 bool
    47 OpenFileFinder::First(OpenFileFinder::Info* aInfo)
    48 {
    49   Close();
    51   mProcDir = opendir("/proc");
    52   if (!mProcDir) {
    53     return false;
    54   }
    55   mState = NEXT_PID;
    56   return Next(aInfo);
    57 }
    59 bool
    60 OpenFileFinder::Next(OpenFileFinder::Info* aInfo)
    61 {
    62   // NOTE: This function calls readdir and readlink, neither of which should
    63   //       block since we're using the proc filesystem, which is a purely
    64   // kernel in-memory filesystem and doesn't depend on external driver
    65   // behaviour.
    66   while (mState != DONE) {
    67     switch (mState) {
    68       case NEXT_PID: {
    69         struct dirent *pidEntry;
    70         pidEntry = readdir(mProcDir);
    71         if (!pidEntry) {
    72           mState = DONE;
    73           break;
    74         }
    75         char *endPtr;
    76         mPid = strtol(pidEntry->d_name, &endPtr, 10);
    77         if (mPid == 0 || *endPtr != '\0') {
    78           // Not a +ve number - ignore
    79           continue;
    80         }
    81         // We've found a /proc/PID directory. Scan open file descriptors.
    82         if (mFdDir) {
    83           closedir(mFdDir);
    84         }
    85         nsPrintfCString fdDirPath("/proc/%d/fd", mPid);
    86         mFdDir = opendir(fdDirPath.get());
    87         if (!mFdDir) {
    88           continue;
    89         }
    90         mState = CHECK_FDS;
    91       }
    92       // Fall through
    93       case CHECK_FDS: {
    94         struct dirent *fdEntry;
    95         while((fdEntry = readdir(mFdDir))) {
    96           if (!strcmp(fdEntry->d_name, ".") ||
    97               !strcmp(fdEntry->d_name, "..")) {
    98             continue;
    99           }
   100           nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name);
   101           nsCString resolvedPath;
   102           if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) {
   103             // We found an open file contained within the directory tree passed
   104             // into the constructor.
   105             FillInfo(aInfo, resolvedPath);
   106             // If sCheckIsB2gOrDescendant is set false, the caller cares about
   107             // all processes which have open files. If sCheckIsB2gOrDescendant
   108             // is set false, we only care about the b2g proccess or its descendants.
   109             if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) {
   110               return true;
   111             }
   112             LOG("Ignore process(%d), not a b2g process or its descendant.",
   113                 aInfo->mPid);
   114           }
   115         }
   116         // We've checked all of the files for this pid, move onto the next one.
   117         mState = NEXT_PID;
   118         continue;
   119       }
   120       case DONE:
   121       default:
   122         mState = DONE;  // covers the default case
   123         break;
   124     }
   125   }
   126   return false;
   127 }
   129 void
   130 OpenFileFinder::Close()
   131 {
   132   if (mFdDir) {
   133     closedir(mFdDir);
   134   }
   135   if (mProcDir) {
   136     closedir(mProcDir);
   137   }
   138 }
   140 void
   141 OpenFileFinder::FillInfo(OpenFileFinder::Info* aInfo, const nsACString& aPath)
   142 {
   143   aInfo->mFileName = aPath;
   144   aInfo->mPid = mPid;
   145   nsPrintfCString exePath("/proc/%d/exe", mPid);
   146   ReadSymLink(exePath, aInfo->mExe);
   147   aInfo->mComm.Truncate();
   148   aInfo->mAppName.Truncate();
   149   nsPrintfCString statPath("/proc/%d/stat", mPid);
   150   nsCString statString;
   151   statString.SetLength(200);
   152   char *stat = statString.BeginWriting();
   153   if (!stat) {
   154     return;
   155   }
   156   ReadSysFile(statPath.get(), stat, statString.Length());
   157   // The stat line includes the comm field, surrounded by parenthesis.
   158   // However, the contents of the comm field itself is arbitrary and
   159   // and can include ')', so we search for the rightmost ) as being
   160   // the end of the comm field.
   161   char *closeParen = strrchr(stat, ')');
   162   if (!closeParen) {
   163     return;
   164   }
   165   char *openParen = strchr(stat, '(');
   166   if (!openParen) {
   167     return;
   168   }
   169   if (openParen >= closeParen) {
   170     return;
   171   }
   172   nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1);
   173   aInfo->mComm = comm;
   174   // There is a single character field after the comm and then
   175   // the parent pid (the field we're interested in).
   176   // ) X ppid
   177   // 01234
   178   int ppid = atoi(&closeParen[4]);
   180   if (mPid == mMyPid) {
   181     // This is chrome process
   182     aInfo->mIsB2gOrDescendant = true;
   183     DBG("Chrome process has open file(s)");
   184     return;
   185   }
   186   // For the rest (non-chrome process), we recursively check the ppid to know
   187   // it is a descendant of b2g or not. See bug 931456.
   188   while (ppid != mMyPid && ppid != 1) {
   189     DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking",
   190         ppid, mMyPid);
   191     nsPrintfCString ppStatPath("/proc/%d/stat", ppid);
   192     ReadSysFile(ppStatPath.get(), stat, statString.Length());
   193     closeParen = strrchr(stat, ')');
   194     if (!closeParen) {
   195       return;
   196     }
   197     ppid = atoi(&closeParen[4]);
   198   }
   199   if (ppid == 1) {
   200     // This is a not a b2g process.
   201     DBG("Non-b2g process has open file(s)");
   202     aInfo->mIsB2gOrDescendant = false;
   203     return;
   204   }
   205   if (ppid == mMyPid) {
   206     // This is a descendant of b2g.
   207     DBG("Child process of chrome process has open file(s)");
   208     aInfo->mIsB2gOrDescendant = true;
   209   }
   211   // This looks like a content process. The comm field will be the
   212   // app name.
   213   aInfo->mAppName = aInfo->mComm;
   214 }
   216 bool
   217 OpenFileFinder::ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath)
   218 {
   219   aOutPath.Truncate();
   220   const char *symLink = aSymLink.BeginReading();
   222   // Verify that we actually have a symlink.
   223   struct stat st;
   224   if (lstat(symLink, &st)) {
   225       return false;
   226   }
   227   if ((st.st_mode & S_IFMT) != S_IFLNK) {
   228       return false;
   229   }
   231   // Contrary to the documentation st.st_size doesn't seem to be a reliable
   232   // indication of the length when reading from /proc, so we use a fixed
   233   // size buffer instead.
   235   char resolvedSymLink[PATH_MAX];
   236   ssize_t pathLength = readlink(symLink, resolvedSymLink,
   237                                 sizeof(resolvedSymLink) - 1);
   238   if (pathLength <= 0) {
   239       return false;
   240   }
   241   resolvedSymLink[pathLength] = '\0';
   242   aOutPath.Assign(resolvedSymLink);
   243   return true;
   244 }
   246 } // system
   247 } // mozilla

mercurial