static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message) { char path[PATH_MAX]; char link[PATH_MAX]; sprintf(path, "/proc/%d/%s", pid, name); if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint)) { char name[PATH_MAX]; GetProcessName(pid, name); LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint); return true; } else return false; }
static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint) { DIR* dir; struct dirent* de; boolean fileOpen = false; char path[PATH_MAX]; char link[PATH_MAX]; int parent_length; // compute path to process's directory of open files sprintf(path, "/proc/%d/fd", pid); dir = opendir(path); if (!dir) return false; // remember length of the path parent_length = strlen(path); // append a trailing '/' path[parent_length++] = '/'; while ((de = readdir(dir)) != 0 && !fileOpen) { if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; // append the file name, after truncating to parent directory path[parent_length] = 0; strcat(path, de->d_name); if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint)) { char name[PATH_MAX]; GetProcessName(pid, name); LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link); fileOpen = true; } } closedir(dir); return fileOpen; }
bool OpenFileFinder::Next(OpenFileFinder::Info* aInfo) { // NOTE: This function calls readdir and readlink, neither of which should // block since we're using the proc filesystem, which is a purely // kernel in-memory filesystem and doesn't depend on external driver // behaviour. while (mState != DONE) { switch (mState) { case NEXT_PID: { struct dirent *pidEntry; pidEntry = readdir(mProcDir); if (!pidEntry) { mState = DONE; break; } char *endPtr; mPid = strtol(pidEntry->d_name, &endPtr, 10); if (mPid == 0 || *endPtr != '\0') { // Not a +ve number - ignore continue; } // We've found a /proc/PID directory. Scan open file descriptors. if (mFdDir) { closedir(mFdDir); } nsPrintfCString fdDirPath("/proc/%d/fd", mPid); mFdDir = opendir(fdDirPath.get()); if (!mFdDir) { continue; } mState = CHECK_FDS; } // Fall through case CHECK_FDS: { struct dirent *fdEntry; while((fdEntry = readdir(mFdDir))) { if (!strcmp(fdEntry->d_name, ".") || !strcmp(fdEntry->d_name, "..")) { continue; } nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name); nsCString resolvedPath; if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) { // We found an open file contained within the directory tree passed // into the constructor. FillInfo(aInfo, resolvedPath); // If sCheckIsB2gOrDescendant is set false, the caller cares about // all processes which have open files. If sCheckIsB2gOrDescendant // is set false, we only care about the b2g proccess or its descendants. if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) { return true; } LOG("Ignore process(%d), not a b2g process or its descendant.", aInfo->mPid); } } // We've checked all of the files for this pid, move onto the next one. mState = NEXT_PID; continue; } case DONE: default: mState = DONE; // covers the default case break; } } return false; }
expand_symlinks P1C(char *, s) { static char pre[BSIZE]; /* return value */ char post[BSIZE], sym[BSIZE], tmp[BSIZE], before[BSIZE]; char *cp; char a; struct stat st; int done; /* Check for symlink loops. It's difficult to check for all the possibilities ourselves, so let the kernel do it. And make it conditional so that people can see where the infinite loop is being caused (see engtools#1536). */ if (!ll_loop) { FILE *f = fopen (s, "r"); if (!f && errno == ELOOP) { /* Not worried about other errors, we'll get to them in due course. */ perror (s); return NULL; } if (f) fclose (f); } strcpy (post, s); strcpy (pre, ""); while (strlen (post) != 0) { CopyFirst (pre, post); if (lstat (pre, &st) != 0) { fprintf (stderr, "lstat(%s) failed ...\n", pre); perror (pre); return NULL; } if (S_ISLNK (st.st_mode)) { ReadSymLink (pre, sym); if (!strncmp (sym, "/", 1)) { if (ll_verbose) printf ("[%s]%s%s -> [%s]%s%s\n", pre, EXPOS, post, sym, EXPOS,post); strcpy (pre, ""); } else { a = pre[0]; /* handle links through the root */ strcpy (tmp, StripLast (pre)); if (!strlen (pre) && a == '/') strcpy (pre, "/"); if (ll_verbose) { sprintf (before, "%s%s[%s]%s%s", pre, EXPRE, tmp, EXPOS, post); printf ("%s -> %s%s[%s]%s%s\n", before, pre, EXPRE, sym, EXPOS,post); } /* Strip "../" path elements from the front of sym; print new result if there were any such elements. */ done = 0; a = pre[0]; /* handle links through the root */ while (!strncmp (sym, "..", 2) && (sym[2] == 0 || sym[2] == '/') && strlen (pre) != 0 && strcmp (pre, ".") && strcmp (pre, "..") && (strlen (pre) < 3 || strcmp (pre + strlen (pre) - 3, "/.."))) { done = 1; StripFirst (sym); StripLast (pre); } if (done && ll_verbose) { for (cp = before; *cp;) *cp++ = ' '; if (strlen (sym)) printf ("%s == %s%s%s%s%s\n", before, pre, EXPRE, sym, EXPOS,post); else printf ("%s == %s%s%s\n", before, pre, EXPOS, post); } if (!strlen (pre) && a == '/') strcpy (pre, "/"); } if (strlen (post) != 0 && strlen (sym) != 0) strcat (sym, "/"); strcat (sym, post); strcpy (post, sym); } } return pre; }
void OpenFileFinder::FillInfo(OpenFileFinder::Info* aInfo, const nsACString& aPath) { aInfo->mFileName = aPath; aInfo->mPid = mPid; nsPrintfCString exePath("/proc/%d/exe", mPid); ReadSymLink(exePath, aInfo->mExe); aInfo->mComm.Truncate(); aInfo->mAppName.Truncate(); nsPrintfCString statPath("/proc/%d/stat", mPid); nsCString statString; statString.SetLength(200); char *stat = statString.BeginWriting(); if (!stat) { return; } ReadSysFile(statPath.get(), stat, statString.Length()); // The stat line includes the comm field, surrounded by parenthesis. // However, the contents of the comm field itself is arbitrary and // and can include ')', so we search for the rightmost ) as being // the end of the comm field. char *closeParen = strrchr(stat, ')'); if (!closeParen) { return; } char *openParen = strchr(stat, '('); if (!openParen) { return; } if (openParen >= closeParen) { return; } nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1); aInfo->mComm = comm; // There is a single character field after the comm and then // the parent pid (the field we're interested in). // ) X ppid // 01234 int ppid = atoi(&closeParen[4]); if (mPid == mMyPid) { // This is chrome process aInfo->mIsB2gOrDescendant = true; DBG("Chrome process has open file(s)"); return; } // For the rest (non-chrome process), we recursively check the ppid to know // it is a descendant of b2g or not. See bug 931456. while (ppid != mMyPid && ppid != 1) { DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking", ppid, mMyPid); nsPrintfCString ppStatPath("/proc/%d/stat", ppid); ReadSysFile(ppStatPath.get(), stat, statString.Length()); closeParen = strrchr(stat, ')'); if (!closeParen) { return; } ppid = atoi(&closeParen[4]); } if (ppid == 1) { // This is a not a b2g process. DBG("Non-b2g process has open file(s)"); aInfo->mIsB2gOrDescendant = false; return; } if (ppid == mMyPid) { // This is a descendant of b2g. DBG("Child process of chrome process has open file(s)"); aInfo->mIsB2gOrDescendant = true; } // This looks like a content process. The comm field will be the // app name. aInfo->mAppName = aInfo->mComm; }